OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
6 // collection infrastructure. | 6 // collection infrastructure. |
7 // | 7 // |
8 // Errors are described at: | 8 // Errors are described at: |
9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
10 | 10 |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 "[blink-gc] Garbage collected class %0" | 129 "[blink-gc] Garbage collected class %0" |
130 " is not permitted to declare a pure-virtual trace method."; | 130 " is not permitted to declare a pure-virtual trace method."; |
131 | 131 |
132 struct BlinkGCPluginOptions { | 132 struct BlinkGCPluginOptions { |
133 BlinkGCPluginOptions() : enable_oilpan(false), dump_graph(false) {} | 133 BlinkGCPluginOptions() : enable_oilpan(false), dump_graph(false) {} |
134 bool enable_oilpan; | 134 bool enable_oilpan; |
135 bool dump_graph; | 135 bool dump_graph; |
136 std::set<std::string> ignored_classes; | 136 std::set<std::string> ignored_classes; |
137 std::set<std::string> checked_namespaces; | 137 std::set<std::string> checked_namespaces; |
138 std::vector<std::string> ignored_directories; | 138 std::vector<std::string> ignored_directories; |
139 std::set<std::string> ignored_base_class_finalizers; | |
139 }; | 140 }; |
140 | 141 |
141 typedef std::vector<CXXRecordDecl*> RecordVector; | 142 typedef std::vector<CXXRecordDecl*> RecordVector; |
142 typedef std::vector<CXXMethodDecl*> MethodVector; | 143 typedef std::vector<CXXMethodDecl*> MethodVector; |
143 | 144 |
144 // Test if a template specialization is an instantiation. | 145 // Test if a template specialization is an instantiation. |
145 static bool IsTemplateInstantiation(CXXRecordDecl* record) { | 146 static bool IsTemplateInstantiation(CXXRecordDecl* record) { |
146 ClassTemplateSpecializationDecl* spec = | 147 ClassTemplateSpecializationDecl* spec = |
147 dyn_cast<ClassTemplateSpecializationDecl>(record); | 148 dyn_cast<ClassTemplateSpecializationDecl>(record); |
148 if (!spec) | 149 if (!spec) |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 json_(0) { | 576 json_(0) { |
576 | 577 |
577 // Only check structures in the blink, WebCore and WebKit namespaces. | 578 // Only check structures in the blink, WebCore and WebKit namespaces. |
578 options_.checked_namespaces.insert("blink"); | 579 options_.checked_namespaces.insert("blink"); |
579 options_.checked_namespaces.insert("WebCore"); | 580 options_.checked_namespaces.insert("WebCore"); |
580 options_.checked_namespaces.insert("WebKit"); | 581 options_.checked_namespaces.insert("WebKit"); |
581 | 582 |
582 // Ignore GC implementation files. | 583 // Ignore GC implementation files. |
583 options_.ignored_directories.push_back("/heap/"); | 584 options_.ignored_directories.push_back("/heap/"); |
584 | 585 |
586 // Following http://crrev.com/369633033 (Blink r177436), | |
587 // ignore WebCore::ScriptWrappable. | |
588 options_.ignored_base_class_finalizers.insert("ScriptWrappable::WebCore"); | |
zerny-chromium
2014/07/07 09:04:33
Lets swap this so it is ns::record
| |
589 | |
585 // Register warning/error messages. | 590 // Register warning/error messages. |
586 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID( | 591 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID( |
587 getErrorLevel(), kClassMustLeftMostlyDeriveGC); | 592 getErrorLevel(), kClassMustLeftMostlyDeriveGC); |
588 diag_class_requires_trace_method_ = | 593 diag_class_requires_trace_method_ = |
589 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod); | 594 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod); |
590 diag_base_requires_tracing_ = | 595 diag_base_requires_tracing_ = |
591 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing); | 596 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing); |
592 diag_fields_require_tracing_ = | 597 diag_fields_require_tracing_ = |
593 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); | 598 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); |
594 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID( | 599 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID( |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
853 dtor, &visitor.finalized_fields()); | 858 dtor, &visitor.finalized_fields()); |
854 } | 859 } |
855 } | 860 } |
856 return; | 861 return; |
857 } | 862 } |
858 | 863 |
859 // Don't require finalization of a mixin that has not yet been "mixed in". | 864 // Don't require finalization of a mixin that has not yet been "mixed in". |
860 if (info->IsGCMixin()) | 865 if (info->IsGCMixin()) |
861 return; | 866 return; |
862 | 867 |
868 // If class has no destructor and all base class destructors can | |
869 // safely be ignored, do not require finalization. | |
870 bool has_relevant_dtors = dtor && dtor->isUserProvided(); | |
871 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); | |
872 !has_relevant_dtors && it != info->GetBases().end(); | |
873 ++it) { | |
874 if (it->second.info()->NeedsFinalization()) | |
875 has_relevant_dtors = !IsIgnoredFinalizableBaseClass(it->second.info()); | |
876 } | |
877 | |
878 if (!has_relevant_dtors) | |
879 return; | |
zerny-chromium
2014/07/07 09:04:33
This will allow erroneous code to pass the plugin,
| |
880 | |
863 // Report the finalization error, and proceed to print possible causes for | 881 // Report the finalization error, and proceed to print possible causes for |
864 // the finalization requirement. | 882 // the finalization requirement. |
865 ReportClassRequiresFinalization(info); | 883 ReportClassRequiresFinalization(info); |
866 | 884 |
867 if (dtor && dtor->isUserProvided()) | 885 if (dtor && dtor->isUserProvided()) |
868 NoteUserDeclaredDestructor(dtor); | 886 NoteUserDeclaredDestructor(dtor); |
869 | 887 |
870 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); | 888 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); |
871 it != info->GetBases().end(); | 889 it != info->GetBases().end(); |
872 ++it) { | 890 ++it) { |
873 if (it->second.info()->NeedsFinalization()) | 891 if (it->second.info()->NeedsFinalization()) |
874 NoteBaseRequiresFinalization(&it->second); | 892 if (!IsIgnoredFinalizableBaseClass(it->second.info())) |
893 NoteBaseRequiresFinalization(&it->second); | |
875 } | 894 } |
876 | 895 |
877 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); | 896 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); |
878 it != info->GetFields().end(); | 897 it != info->GetFields().end(); |
879 ++it) { | 898 ++it) { |
880 if (it->second.edge()->NeedsFinalization()) | 899 if (it->second.edge()->NeedsFinalization()) |
881 NoteField(&it->second, diag_field_requires_finalization_note_); | 900 NoteField(&it->second, diag_field_requires_finalization_note_); |
882 } | 901 } |
883 } | 902 } |
884 | 903 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1077 bool IsIgnoredClass(RecordInfo* info) { | 1096 bool IsIgnoredClass(RecordInfo* info) { |
1078 // Ignore any class prefixed by SameSizeAs. These are used in | 1097 // Ignore any class prefixed by SameSizeAs. These are used in |
1079 // Blink to verify class sizes and don't need checking. | 1098 // Blink to verify class sizes and don't need checking. |
1080 const string SameSizeAs = "SameSizeAs"; | 1099 const string SameSizeAs = "SameSizeAs"; |
1081 if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0) | 1100 if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0) |
1082 return true; | 1101 return true; |
1083 return options_.ignored_classes.find(info->name()) != | 1102 return options_.ignored_classes.find(info->name()) != |
1084 options_.ignored_classes.end(); | 1103 options_.ignored_classes.end(); |
1085 } | 1104 } |
1086 | 1105 |
1106 bool IsIgnoredFinalizableBaseClass(RecordInfo* info) { | |
1107 NamespaceDecl* ns = | |
1108 dyn_cast<NamespaceDecl>(info->record()->getDeclContext()); | |
1109 if (!ns) | |
1110 return false; | |
1111 | |
1112 string qualified_name = | |
1113 string(info->name()).append("::").append(ns->getName()); | |
1114 return options_.ignored_base_class_finalizers.find(qualified_name) != | |
1115 options_.ignored_base_class_finalizers.end(); | |
1116 } | |
1117 | |
1087 bool InIgnoredDirectory(RecordInfo* info) { | 1118 bool InIgnoredDirectory(RecordInfo* info) { |
1088 string filename; | 1119 string filename; |
1089 if (!GetFilename(info->record()->getLocStart(), &filename)) | 1120 if (!GetFilename(info->record()->getLocStart(), &filename)) |
1090 return false; // TODO: should we ignore non-existing file locations? | 1121 return false; // TODO: should we ignore non-existing file locations? |
1091 std::vector<string>::iterator it = options_.ignored_directories.begin(); | 1122 std::vector<string>::iterator it = options_.ignored_directories.begin(); |
1092 for (; it != options_.ignored_directories.end(); ++it) | 1123 for (; it != options_.ignored_directories.end(); ++it) |
1093 if (filename.find(*it) != string::npos) | 1124 if (filename.find(*it) != string::npos) |
1094 return true; | 1125 return true; |
1095 return false; | 1126 return false; |
1096 } | 1127 } |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1477 | 1508 |
1478 private: | 1509 private: |
1479 BlinkGCPluginOptions options_; | 1510 BlinkGCPluginOptions options_; |
1480 }; | 1511 }; |
1481 | 1512 |
1482 } // namespace | 1513 } // namespace |
1483 | 1514 |
1484 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1515 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
1485 "blink-gc-plugin", | 1516 "blink-gc-plugin", |
1486 "Check Blink GC invariants"); | 1517 "Check Blink GC invariants"); |
OLD | NEW |