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 |
| 11 #include "Config.h" | 11 #include "Config.h" |
| 12 #include "JsonWriter.h" | 12 #include "JsonWriter.h" |
| 13 #include "RecordInfo.h" | 13 #include "RecordInfo.h" |
| 14 | 14 |
| 15 #include "clang/AST/AST.h" | 15 #include "clang/AST/AST.h" |
| 16 #include "clang/AST/ASTConsumer.h" | 16 #include "clang/AST/ASTConsumer.h" |
| 17 #include "clang/AST/RecursiveASTVisitor.h" | 17 #include "clang/AST/RecursiveASTVisitor.h" |
| 18 #include "clang/Frontend/CompilerInstance.h" | 18 #include "clang/Frontend/CompilerInstance.h" |
| 19 #include "clang/Frontend/FrontendPluginRegistry.h" | 19 #include "clang/Frontend/FrontendPluginRegistry.h" |
| 20 #include "clang/Sema/Sema.h" | |
| 20 | 21 |
| 21 using namespace clang; | 22 using namespace clang; |
| 22 using std::string; | 23 using std::string; |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 const char kClassMustLeftMostlyDeriveGC[] = | 27 const char kClassMustLeftMostlyDeriveGC[] = |
| 27 "[blink-gc] Class %0 must derive its GC base in the left-most position."; | 28 "[blink-gc] Class %0 must derive its GC base in the left-most position."; |
| 28 | 29 |
| 29 const char kClassRequiresTraceMethod[] = | 30 const char kClassRequiresTraceMethod[] = |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 " must be polymorphic."; | 138 " must be polymorphic."; |
| 138 | 139 |
| 139 const char kBaseClassMustDeclareVirtualTrace[] = | 140 const char kBaseClassMustDeclareVirtualTrace[] = |
| 140 "[blink-gc] Left-most base class %0 of derived class %1" | 141 "[blink-gc] Left-most base class %0 of derived class %1" |
| 141 " must define a virtual trace method."; | 142 " must define a virtual trace method."; |
| 142 | 143 |
| 143 const char kClassMustDeclareGCMixinTraceMethod[] = | 144 const char kClassMustDeclareGCMixinTraceMethod[] = |
| 144 "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must" | 145 "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must" |
| 145 " locally declare and override trace(Visitor*)"; | 146 " locally declare and override trace(Visitor*)"; |
| 146 | 147 |
| 148 // Use a local RAV implementation to simply collect all FunctionDecls marked for | |
| 149 // late template parsing. This happens with the flag -fdelayed-template-parsing, | |
| 150 // which is on by default in MSVC-compatible mode. | |
| 151 std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) { | |
| 152 struct Visitor : public RecursiveASTVisitor<Visitor> { | |
| 153 bool VisitFunctionDecl(FunctionDecl* function_decl) { | |
| 154 if (function_decl->isLateTemplateParsed()) | |
| 155 late_parsed_decls.insert(function_decl); | |
| 156 return true; | |
| 157 } | |
| 158 | |
| 159 std::set<FunctionDecl*> late_parsed_decls; | |
| 160 } v; | |
| 161 v.TraverseDecl(decl); | |
| 162 return v.late_parsed_decls; | |
| 163 } | |
| 164 | |
| 147 struct BlinkGCPluginOptions { | 165 struct BlinkGCPluginOptions { |
| 148 BlinkGCPluginOptions() | 166 BlinkGCPluginOptions() |
| 149 : enable_oilpan(false) | 167 : enable_oilpan(false) |
| 150 , dump_graph(false) | 168 , dump_graph(false) |
| 151 , warn_raw_ptr(false) | 169 , warn_raw_ptr(false) |
| 152 , warn_unneeded_finalizer(false) {} | 170 , warn_unneeded_finalizer(false) {} |
| 153 bool enable_oilpan; | 171 bool enable_oilpan; |
| 154 bool dump_graph; | 172 bool dump_graph; |
| 155 bool warn_raw_ptr; | 173 bool warn_raw_ptr; |
| 156 bool warn_unneeded_finalizer; | 174 bool warn_unneeded_finalizer; |
| (...skipping 853 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1010 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); | 1028 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); |
| 1011 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( | 1029 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( |
| 1012 DiagnosticsEngine::Note, kManualDispatchMethodNote); | 1030 DiagnosticsEngine::Note, kManualDispatchMethodNote); |
| 1013 } | 1031 } |
| 1014 | 1032 |
| 1015 void HandleTranslationUnit(ASTContext& context) override { | 1033 void HandleTranslationUnit(ASTContext& context) override { |
| 1016 // Don't run the plugin if the compilation unit is already invalid. | 1034 // Don't run the plugin if the compilation unit is already invalid. |
| 1017 if (diagnostic_.hasErrorOccurred()) | 1035 if (diagnostic_.hasErrorOccurred()) |
| 1018 return; | 1036 return; |
| 1019 | 1037 |
| 1038 ParseFunctionTemplates(context.getTranslationUnitDecl()); | |
| 1039 | |
| 1020 CollectVisitor visitor; | 1040 CollectVisitor visitor; |
| 1021 visitor.TraverseDecl(context.getTranslationUnitDecl()); | 1041 visitor.TraverseDecl(context.getTranslationUnitDecl()); |
| 1022 | 1042 |
| 1023 if (options_.dump_graph) { | 1043 if (options_.dump_graph) { |
| 1024 std::error_code err; | 1044 std::error_code err; |
| 1025 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work. | 1045 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work. |
| 1026 json_ = JsonWriter::from(instance_.createOutputFile( | 1046 json_ = JsonWriter::from(instance_.createOutputFile( |
| 1027 "", // OutputPath | 1047 "", // OutputPath |
| 1028 err, // Errors | 1048 err, // Errors |
| 1029 true, // Binary | 1049 true, // Binary |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1056 CheckTracingMethod(*it); | 1076 CheckTracingMethod(*it); |
| 1057 } | 1077 } |
| 1058 | 1078 |
| 1059 if (json_) { | 1079 if (json_) { |
| 1060 json_->CloseList(); | 1080 json_->CloseList(); |
| 1061 delete json_; | 1081 delete json_; |
| 1062 json_ = 0; | 1082 json_ = 0; |
| 1063 } | 1083 } |
| 1064 } | 1084 } |
| 1065 | 1085 |
| 1086 void ParseFunctionTemplates(TranslationUnitDecl* decl) { | |
| 1087 std::set<FunctionDecl*> late_parsed_decls = | |
| 1088 GetLateParsedFunctionDecls(decl); | |
|
Reid Kleckner
2015/05/15 22:44:32
Traversing the whole AST might be expensive. Maybe
Nico
2015/05/15 22:57:26
We always build with asserts enabled, so that woul
| |
| 1089 clang::Sema& sema = instance_.getSema(); | |
| 1090 | |
| 1091 // If we have any late-parsed functions, make sure the | |
| 1092 // -fdelayed-template-parsing flag is on. Otherwise we don't know where | |
| 1093 // they came from. | |
| 1094 assert((instance_.getLangOpts().DelayedTemplateParsing || | |
| 1095 late_parsed_decls.empty()) && | |
| 1096 "Should not have late-parsed decls without " | |
| 1097 "-fdelayed-template-parsing."); | |
| 1098 | |
| 1099 for (const FunctionDecl* fd : late_parsed_decls) { | |
| 1100 assert(fd->isLateTemplateParsed()); | |
| 1101 | |
| 1102 if (!Config::IsTraceMethod(fd)) | |
| 1103 continue; | |
| 1104 | |
| 1105 if (instance_.getSourceManager().isInSystemHeader( | |
| 1106 instance_.getSourceManager().getSpellingLoc(fd->getLocation()))) | |
| 1107 continue; | |
| 1108 | |
| 1109 // Force parsing and AST building of the yet-uninstantiated function | |
| 1110 // template trace method bodies. | |
| 1111 clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd]; | |
| 1112 sema.LateTemplateParser(sema.OpaqueParser, *lpt); | |
| 1113 } | |
| 1114 } | |
| 1115 | |
| 1066 // Main entry for checking a record declaration. | 1116 // Main entry for checking a record declaration. |
| 1067 void CheckRecord(RecordInfo* info) { | 1117 void CheckRecord(RecordInfo* info) { |
| 1068 if (IsIgnored(info)) | 1118 if (IsIgnored(info)) |
| 1069 return; | 1119 return; |
| 1070 | 1120 |
| 1071 CXXRecordDecl* record = info->record(); | 1121 CXXRecordDecl* record = info->record(); |
| 1072 | 1122 |
| 1073 // TODO: what should we do to check unions? | 1123 // TODO: what should we do to check unions? |
| 1074 if (record->isUnion()) | 1124 if (record->isUnion()) |
| 1075 return; | 1125 return; |
| (...skipping 978 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2054 | 2104 |
| 2055 private: | 2105 private: |
| 2056 BlinkGCPluginOptions options_; | 2106 BlinkGCPluginOptions options_; |
| 2057 }; | 2107 }; |
| 2058 | 2108 |
| 2059 } // namespace | 2109 } // namespace |
| 2060 | 2110 |
| 2061 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 2111 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
| 2062 "blink-gc-plugin", | 2112 "blink-gc-plugin", |
| 2063 "Check Blink GC invariants"); | 2113 "Check Blink GC invariants"); |
| OLD | NEW |