Chromium Code Reviews| 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 |