Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp

Issue 817653003: Update from https://crrev.com/309717 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/android/forwarder2/host_forwarder_main.cc ('k') | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 190
191 // Collect record declarations, including nested declarations. 191 // Collect record declarations, including nested declarations.
192 bool VisitCXXRecordDecl(CXXRecordDecl* record) { 192 bool VisitCXXRecordDecl(CXXRecordDecl* record) {
193 if (record->hasDefinition() && record->isCompleteDefinition()) 193 if (record->hasDefinition() && record->isCompleteDefinition())
194 record_decls_.push_back(record); 194 record_decls_.push_back(record);
195 return true; 195 return true;
196 } 196 }
197 197
198 // Collect tracing method definitions, but don't traverse method bodies. 198 // Collect tracing method definitions, but don't traverse method bodies.
199 bool TraverseCXXMethodDecl(CXXMethodDecl* method) { 199 bool TraverseCXXMethodDecl(CXXMethodDecl* method) {
200 if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method)) 200 if (method->isThisDeclarationADefinition() &&
201 Config::IsTraceMethod(method, nullptr))
201 trace_decls_.push_back(method); 202 trace_decls_.push_back(method);
202 return true; 203 return true;
203 } 204 }
204 205
205 private: 206 private:
206 RecordVector record_decls_; 207 RecordVector record_decls_;
207 MethodVector trace_decls_; 208 MethodVector trace_decls_;
208 }; 209 };
209 210
210 // This visitor checks that a finalizer method does not have invalid access to 211 // This visitor checks that a finalizer method does not have invalid access to
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 RecordInfo* receiver_; 316 RecordInfo* receiver_;
316 bool dispatched_to_receiver_; 317 bool dispatched_to_receiver_;
317 }; 318 };
318 319
319 // This visitor checks a tracing method by traversing its body. 320 // This visitor checks a tracing method by traversing its body.
320 // - A member field is considered traced if it is referenced in the body. 321 // - A member field is considered traced if it is referenced in the body.
321 // - A base is traced if a base-qualified call to a trace method is found. 322 // - A base is traced if a base-qualified call to a trace method is found.
322 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { 323 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
323 public: 324 public:
324 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) 325 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info)
325 : trace_(trace), info_(info) {} 326 : trace_(trace), info_(info), delegates_to_traceimpl_(false) {}
327
328 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; }
326 329
327 bool VisitMemberExpr(MemberExpr* member) { 330 bool VisitMemberExpr(MemberExpr* member) {
328 // In weak callbacks, consider any occurrence as a correct usage. 331 // In weak callbacks, consider any occurrence as a correct usage.
329 // TODO: We really want to require that isAlive is checked on manually 332 // TODO: We really want to require that isAlive is checked on manually
330 // processed weak fields. 333 // processed weak fields.
331 if (IsWeakCallback()) { 334 if (IsWeakCallback()) {
332 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) 335 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()))
333 FoundField(field); 336 FoundField(field);
334 } 337 }
335 return true; 338 return true;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 return true; 379 return true;
377 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); 380 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
378 if (decl) 381 if (decl)
379 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); 382 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
380 return true; 383 return true;
381 } 384 }
382 385
383 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { 386 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) {
384 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) 387 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr))
385 return true; 388 return true;
389
390 if (expr->getMethodDecl()->getNameAsString() == kTraceImplName) {
391 delegates_to_traceimpl_ = true;
392 return true;
393 }
386 } 394 }
387 395
388 CheckTraceBaseCall(call); 396 CheckTraceBaseCall(call);
389 return true; 397 return true;
390 } 398 }
391 399
392 private: 400 private:
393 401
394 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { 402 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) {
395 NestedNameSpecifier* qual = expr->getQualifier(); 403 NestedNameSpecifier* qual = expr->getQualifier();
396 if (!qual) 404 if (!qual)
397 return 0; 405 return 0;
398 406
399 const Type* type = qual->getAsType(); 407 const Type* type = qual->getAsType();
400 if (!type) 408 if (!type)
401 return 0; 409 return 0;
402 410
403 const TemplateSpecializationType* tmpl_type = 411 return RecordInfo::GetDependentTemplatedDecl(*type);
404 type->getAs<TemplateSpecializationType>();
405 if (!tmpl_type)
406 return 0;
407
408 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl();
409 if (!tmpl_decl)
410 return 0;
411
412 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl());
413 } 412 }
414 413
415 void CheckCXXDependentScopeMemberExpr(CallExpr* call, 414 void CheckCXXDependentScopeMemberExpr(CallExpr* call,
416 CXXDependentScopeMemberExpr* expr) { 415 CXXDependentScopeMemberExpr* expr) {
417 string fn_name = expr->getMember().getAsString(); 416 string fn_name = expr->getMember().getAsString();
417
418 // Check for VisitorDispatcher::trace(field)
419 if (!expr->isImplicitAccess()) {
420 if (clang::DeclRefExpr* base_decl =
421 clang::dyn_cast<clang::DeclRefExpr>(expr->getBase())) {
422 if (Config::IsVisitorDispatcherType(base_decl->getType()) &&
423 call->getNumArgs() == 1 && fn_name == kTraceName) {
424 FindFieldVisitor finder;
425 finder.TraverseStmt(call->getArg(0));
426 if (finder.field())
427 FoundField(finder.field());
428
429 return;
430 }
431 }
432 }
433
418 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); 434 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr);
419 if (!tmpl) 435 if (!tmpl)
420 return; 436 return;
421 437
422 // Check for Super<T>::trace(visitor) 438 // Check for Super<T>::trace(visitor)
423 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) { 439 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) {
424 RecordInfo::Bases::iterator it = info_->GetBases().begin(); 440 RecordInfo::Bases::iterator it = info_->GetBases().begin();
425 for (; it != info_->GetBases().end(); ++it) { 441 for (; it != info_->GetBases().end(); ++it) {
426 if (it->first->getName() == tmpl->getName()) 442 if (it->first->getName() == tmpl->getName())
427 it->second.MarkTraced(); 443 it->second.MarkTraced();
(...skipping 10 matching lines...) Expand all
438 FoundField(finder.field()); 454 FoundField(finder.field());
439 } 455 }
440 } 456 }
441 457
442 bool CheckTraceBaseCall(CallExpr* call) { 458 bool CheckTraceBaseCall(CallExpr* call) {
443 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); 459 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee());
444 if (!callee) 460 if (!callee)
445 return false; 461 return false;
446 462
447 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); 463 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl());
448 if (!fn || !Config::IsTraceMethod(fn)) 464 if (!fn || !Config::IsTraceMethod(fn, nullptr))
449 return false; 465 return false;
450 466
451 // Currently, a manually dispatched class cannot have mixin bases (having 467 // Currently, a manually dispatched class cannot have mixin bases (having
452 // one would add a vtable which we explicitly check against). This means 468 // one would add a vtable which we explicitly check against). This means
453 // that we can only make calls to a trace method of the same name. Revisit 469 // that we can only make calls to a trace method of the same name. Revisit
454 // this if our mixin/vtable assumption changes. 470 // this if our mixin/vtable assumption changes.
455 if (fn->getName() != trace_->getName()) 471 if (fn->getName() != trace_->getName())
456 return false; 472 return false;
457 473
458 CXXRecordDecl* decl = 0; 474 CXXRecordDecl* decl = 0;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 } 574 }
559 } else { 575 } else {
560 RecordInfo::Fields::iterator it = info_->GetFields().find(field); 576 RecordInfo::Fields::iterator it = info_->GetFields().find(field);
561 if (it != info_->GetFields().end()) 577 if (it != info_->GetFields().end())
562 MarkTraced(it); 578 MarkTraced(it);
563 } 579 }
564 } 580 }
565 581
566 CXXMethodDecl* trace_; 582 CXXMethodDecl* trace_;
567 RecordInfo* info_; 583 RecordInfo* info_;
584 bool delegates_to_traceimpl_;
568 }; 585 };
569 586
570 // This visitor checks that the fields of a class and the fields of 587 // This visitor checks that the fields of a class and the fields of
571 // its part objects don't define GC roots. 588 // its part objects don't define GC roots.
572 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { 589 class CheckGCRootsVisitor : public RecursiveEdgeVisitor {
573 public: 590 public:
574 typedef std::vector<FieldPoint*> RootPath; 591 typedef std::vector<FieldPoint*> RootPath;
575 typedef std::set<RecordInfo*> VisitingSet; 592 typedef std::set<RecordInfo*> VisitingSet;
576 typedef std::vector<RootPath> Errors; 593 typedef std::vector<RootPath> Errors;
577 594
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after
1035 // ensure that the left-most base defines a vtable. This ensures that the 1052 // ensure that the left-most base defines a vtable. This ensures that the
1036 // first thing to be initialized when constructing the object is the vtable 1053 // first thing to be initialized when constructing the object is the vtable
1037 // itself. 1054 // itself.
1038 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) { 1055 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) {
1039 CXXRecordDecl* left_most = info->record(); 1056 CXXRecordDecl* left_most = info->record();
1040 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1057 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
1041 CXXRecordDecl* left_most_base = 0; 1058 CXXRecordDecl* left_most_base = 0;
1042 while (it != left_most->bases_end()) { 1059 while (it != left_most->bases_end()) {
1043 left_most_base = it->getType()->getAsCXXRecordDecl(); 1060 left_most_base = it->getType()->getAsCXXRecordDecl();
1044 if (!left_most_base && it->getType()->isDependentType()) 1061 if (!left_most_base && it->getType()->isDependentType())
1045 left_most_base = GetDependentTemplatedDecl(*it->getType()); 1062 left_most_base = RecordInfo::GetDependentTemplatedDecl(*it->getType());
1046 1063
1047 // TODO: Find a way to correctly check actual instantiations 1064 // TODO: Find a way to correctly check actual instantiations
1048 // for dependent types. The escape below will be hit, eg, when 1065 // for dependent types. The escape below will be hit, eg, when
1049 // we have a primary template with no definition and 1066 // we have a primary template with no definition and
1050 // specializations for each case (such as SupplementBase) in 1067 // specializations for each case (such as SupplementBase) in
1051 // which case we don't succeed in checking the required 1068 // which case we don't succeed in checking the required
1052 // properties. 1069 // properties.
1053 if (!left_most_base || !left_most_base->hasDefinition()) 1070 if (!left_most_base || !left_most_base->hasDefinition())
1054 return; 1071 return;
1055 1072
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1096 } 1113 }
1097 } 1114 }
1098 ReportLeftMostBaseMustBePolymorphic(info, left_most); 1115 ReportLeftMostBaseMustBePolymorphic(info, left_most);
1099 } 1116 }
1100 } 1117 }
1101 1118
1102 CXXRecordDecl* GetLeftMostBase(CXXRecordDecl* left_most) { 1119 CXXRecordDecl* GetLeftMostBase(CXXRecordDecl* left_most) {
1103 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1120 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
1104 while (it != left_most->bases_end()) { 1121 while (it != left_most->bases_end()) {
1105 if (it->getType()->isDependentType()) 1122 if (it->getType()->isDependentType())
1106 left_most = GetDependentTemplatedDecl(*it->getType()); 1123 left_most = RecordInfo::GetDependentTemplatedDecl(*it->getType());
1107 else 1124 else
1108 left_most = it->getType()->getAsCXXRecordDecl(); 1125 left_most = it->getType()->getAsCXXRecordDecl();
1109 if (!left_most || !left_most->hasDefinition()) 1126 if (!left_most || !left_most->hasDefinition())
1110 return 0; 1127 return 0;
1111 it = left_most->bases_begin(); 1128 it = left_most->bases_begin();
1112 } 1129 }
1113 return left_most; 1130 return left_most;
1114 } 1131 }
1115 1132
1116 bool DeclaresVirtualMethods(CXXRecordDecl* decl) { 1133 bool DeclaresVirtualMethods(CXXRecordDecl* decl) {
1117 CXXRecordDecl::method_iterator it = decl->method_begin(); 1134 CXXRecordDecl::method_iterator it = decl->method_begin();
1118 for (; it != decl->method_end(); ++it) 1135 for (; it != decl->method_end(); ++it)
1119 if (it->isVirtual() && !it->isPure()) 1136 if (it->isVirtual() && !it->isPure())
1120 return true; 1137 return true;
1121 return false; 1138 return false;
1122 } 1139 }
1123 1140
1124 void CheckLeftMostDerived(RecordInfo* info) { 1141 void CheckLeftMostDerived(RecordInfo* info) {
1125 CXXRecordDecl* left_most = info->record(); 1142 CXXRecordDecl* left_most = GetLeftMostBase(info->record());
1126 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1143 if (!left_most)
1127 while (it != left_most->bases_end()) { 1144 return;
1128 left_most = it->getType()->getAsCXXRecordDecl();
1129 it = left_most->bases_begin();
1130 }
1131 if (!Config::IsGCBase(left_most->getName())) 1145 if (!Config::IsGCBase(left_most->getName()))
1132 ReportClassMustLeftMostlyDeriveGC(info); 1146 ReportClassMustLeftMostlyDeriveGC(info);
1133 } 1147 }
1134 1148
1135 void CheckDispatch(RecordInfo* info) { 1149 void CheckDispatch(RecordInfo* info) {
1136 bool finalized = info->IsGCFinalized(); 1150 bool finalized = info->IsGCFinalized();
1137 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod(); 1151 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod();
1138 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod(); 1152 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod();
1139 if (!trace_dispatch && !finalize_dispatch) 1153 if (!trace_dispatch && !finalize_dispatch)
1140 return; 1154 return;
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1296 ++it) { 1310 ++it) {
1297 RecordInfo* base = it->second.info(); 1311 RecordInfo* base = it->second.info();
1298 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) 1312 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
1299 ReportOverriddenNonVirtualTrace(parent, trace, other); 1313 ReportOverriddenNonVirtualTrace(parent, trace, other);
1300 } 1314 }
1301 } 1315 }
1302 1316
1303 CheckTraceVisitor visitor(trace, parent); 1317 CheckTraceVisitor visitor(trace, parent);
1304 visitor.TraverseCXXMethodDecl(trace); 1318 visitor.TraverseCXXMethodDecl(trace);
1305 1319
1320 // Skip reporting if this trace method is a just delegate to
1321 // traceImpl method. We will report on CheckTraceMethod on traceImpl method.
1322 if (visitor.delegates_to_traceimpl())
1323 return;
1324
1306 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1325 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1307 it != parent->GetBases().end(); 1326 it != parent->GetBases().end();
1308 ++it) { 1327 ++it) {
1309 if (!it->second.IsProperlyTraced()) 1328 if (!it->second.IsProperlyTraced())
1310 ReportBaseRequiresTracing(parent, trace, it->first); 1329 ReportBaseRequiresTracing(parent, trace, it->first);
1311 } 1330 }
1312 1331
1313 for (RecordInfo::Fields::iterator it = parent->GetFields().begin(); 1332 for (RecordInfo::Fields::iterator it = parent->GetFields().begin();
1314 it != parent->GetFields().end(); 1333 it != parent->GetFields().end();
1315 ++it) { 1334 ++it) {
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
1887 1906
1888 private: 1907 private:
1889 BlinkGCPluginOptions options_; 1908 BlinkGCPluginOptions options_;
1890 }; 1909 };
1891 1910
1892 } // namespace 1911 } // namespace
1893 1912
1894 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 1913 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1895 "blink-gc-plugin", 1914 "blink-gc-plugin",
1896 "Check Blink GC invariants"); 1915 "Check Blink GC invariants");
OLDNEW
« no previous file with comments | « tools/android/forwarder2/host_forwarder_main.cc ('k') | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698