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 3 // found in the LICENSE file. 4 5 // This clang plugin checks various invariants of the Blink garbage 6 // collection infrastructure. 7 // 8 // Errors are described at: 9 // http://www.chromium.org/developers/blink-gc-plugin-errors 10 11 #include "Config.h" 12 #include "JsonWriter.h" 13 #include "RecordInfo.h" 14 15 #include "clang/AST/AST.h" 16 #include "clang/AST/ASTConsumer.h" 17 #include "clang/AST/RecursiveASTVisitor.h" 18 #include "clang/Frontend/CompilerInstance.h" 19 #include "clang/Frontend/FrontendPluginRegistry.h" 20 21 using namespace clang; 22 using std::string; 23 24 namespace { 25 26 const char kClassMustLeftMostlyDeriveGC[] = 27 "[blink-gc] Class %0 must derive its GC base in the left-most position."; 28 29 const char kClassRequiresTraceMethod[] = 30 "[blink-gc] Class %0 requires a trace method."; 31 32 const char kBaseRequiresTracing[] = 33 "[blink-gc] Base class %0 of derived class %1 requires tracing."; 34 35 const char kBaseRequiresTracingNote[] = 36 "[blink-gc] Untraced base class %0 declared here:"; 37 38 const char kFieldsRequireTracing[] = 39 "[blink-gc] Class %0 has untraced fields that require tracing."; 40 41 const char kFieldRequiresTracingNote[] = 42 "[blink-gc] Untraced field %0 declared here:"; 43 44 const char kClassContainsInvalidFields[] = 45 "[blink-gc] Class %0 contains invalid fields."; 46 47 const char kClassContainsGCRoot[] = 48 "[blink-gc] Class %0 contains GC root in field %1."; 49 50 const char kClassRequiresFinalization[] = 51 "[blink-gc] Class %0 requires finalization."; 52 53 const char kClassDoesNotRequireFinalization[] = 54 "[blink-gc] Class %0 may not require finalization."; 55 56 const char kFinalizerAccessesFinalizedField[] = 57 "[blink-gc] Finalizer %0 accesses potentially finalized field %1."; 58 59 const char kRawPtrToGCManagedClassNote[] = 60 "[blink-gc] Raw pointer field %0 to a GC managed class declared here:"; 61 62 const char kRefPtrToGCManagedClassNote[] = 63 "[blink-gc] RefPtr field %0 to a GC managed class declared here:"; 64 65 const char kOwnPtrToGCManagedClassNote[] = 66 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; 67 68 const char kStackAllocatedFieldNote[] = 69 "[blink-gc] Stack-allocated field %0 declared here:"; 70 71 const char kMemberInUnmanagedClassNote[] = 72 "[blink-gc] Member field %0 in unmanaged class declared here:"; 73 74 const char kPartObjectToGCDerivedClassNote[] = 75 "[blink-gc] Part-object field %0 to a GC derived class declared here:"; 76 77 const char kPartObjectContainsGCRootNote[] = 78 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; 79 80 const char kFieldContainsGCRootNote[] = 81 "[blink-gc] Field %0 defining a GC root declared here:"; 82 83 const char kOverriddenNonVirtualTrace[] = 84 "[blink-gc] Class %0 overrides non-virtual trace of base class %1."; 85 86 const char kOverriddenNonVirtualTraceNote[] = 87 "[blink-gc] Non-virtual trace method declared here:"; 88 89 const char kMissingTraceDispatchMethod[] = 90 "[blink-gc] Class %0 is missing manual trace dispatch."; 91 92 const char kMissingFinalizeDispatchMethod[] = 93 "[blink-gc] Class %0 is missing manual finalize dispatch."; 94 95 const char kVirtualAndManualDispatch[] = 96 "[blink-gc] Class %0 contains or inherits virtual methods" 97 " but implements manual dispatching."; 98 99 const char kMissingTraceDispatch[] = 100 "[blink-gc] Missing dispatch to class %0 in manual trace dispatch."; 101 102 const char kMissingFinalizeDispatch[] = 103 "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch."; 104 105 const char kFinalizedFieldNote[] = 106 "[blink-gc] Potentially finalized field %0 declared here:"; 107 108 const char kUserDeclaredDestructorNote[] = 109 "[blink-gc] User-declared destructor declared here:"; 110 111 const char kUserDeclaredFinalizerNote[] = 112 "[blink-gc] User-declared finalizer declared here:"; 113 114 const char kBaseRequiresFinalizationNote[] = 115 "[blink-gc] Base class %0 requiring finalization declared here:"; 116 117 const char kFieldRequiresFinalizationNote[] = 118 "[blink-gc] Field %0 requiring finalization declared here:"; 119 120 const char kManualDispatchMethodNote[] = 121 "[blink-gc] Manual dispatch %0 declared here:"; 122 123 const char kDerivesNonStackAllocated[] = 124 "[blink-gc] Stack-allocated class %0 derives class %1" 125 " which is not stack allocated."; 126 127 const char kClassOverridesNew[] = 128 "[blink-gc] Garbage collected class %0" 129 " is not permitted to override its new operator."; 130 131 const char kClassDeclaresPureVirtualTrace[] = 132 "[blink-gc] Garbage collected class %0" 133 " is not permitted to declare a pure-virtual trace method."; 134 135 const char kLeftMostBaseMustBePolymorphic[] = 136 "[blink-gc] Left-most base class %0 of derived class %1" 137 " must be polymorphic."; 138 139 const char kBaseClassMustDeclareVirtualTrace[] = 140 "[blink-gc] Left-most base class %0 of derived class %1" 141 " must define a virtual trace method."; 142 143 struct BlinkGCPluginOptions { 144 BlinkGCPluginOptions() 145 : enable_oilpan(false) 146 , dump_graph(false) 147 , warn_raw_ptr(false) 148 , warn_unneeded_finalizer(false) {} 149 bool enable_oilpan; 150 bool dump_graph; 151 bool warn_raw_ptr; 152 bool warn_unneeded_finalizer; 153 std::set<std::string> ignored_classes; 154 std::set<std::string> checked_namespaces; 155 std::vector<std::string> ignored_directories; 156 }; 157 158 typedef std::vector<CXXRecordDecl*> RecordVector; 159 typedef std::vector<CXXMethodDecl*> MethodVector; 160 161 // Test if a template specialization is an instantiation. 162 static bool IsTemplateInstantiation(CXXRecordDecl* record) { 163 ClassTemplateSpecializationDecl* spec = 164 dyn_cast<ClassTemplateSpecializationDecl>(record); 165 if (!spec) 166 return false; 167 switch (spec->getTemplateSpecializationKind()) { 168 case TSK_ImplicitInstantiation: 169 case TSK_ExplicitInstantiationDefinition: 170 return true; 171 case TSK_Undeclared: 172 case TSK_ExplicitSpecialization: 173 return false; 174 // TODO: unsupported cases. 175 case TSK_ExplicitInstantiationDeclaration: 176 return false; 177 } 178 assert(false && "Unknown template specialization kind"); 179 } 180 181 // This visitor collects the entry points for the checker. 182 class CollectVisitor : public RecursiveASTVisitor<CollectVisitor> { 183 public: 184 CollectVisitor() {} 185 186 RecordVector& record_decls() { return record_decls_; } 187 MethodVector& trace_decls() { return trace_decls_; } 188 189 bool shouldVisitTemplateInstantiations() { return false; } 190 191 // Collect record declarations, including nested declarations. 192 bool VisitCXXRecordDecl(CXXRecordDecl* record) { 193 if (record->hasDefinition() && record->isCompleteDefinition()) 194 record_decls_.push_back(record); 195 return true; 196 } 197 198 // Collect tracing method definitions, but don't traverse method bodies. 199 bool TraverseCXXMethodDecl(CXXMethodDecl* method) { 200 if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method)) 201 trace_decls_.push_back(method); 202 return true; 203 } 204 205 private: 206 RecordVector record_decls_; 207 MethodVector trace_decls_; 208 }; 209 210 // This visitor checks that a finalizer method does not have invalid access to 211 // fields that are potentially finalized. A potentially finalized field is 212 // either a Member, a heap-allocated collection or an off-heap collection that 213 // contains Members. Invalid uses are currently identified as passing the field 214 // as the argument of a procedure call or using the -> or [] operators on it. 215 class CheckFinalizerVisitor 216 : public RecursiveASTVisitor<CheckFinalizerVisitor> { 217 private: 218 // Simple visitor to determine if the content of a field might be collected 219 // during finalization. 220 class MightBeCollectedVisitor : public EdgeVisitor { 221 public: 222 MightBeCollectedVisitor() : might_be_collected_(false) {} 223 bool might_be_collected() { return might_be_collected_; } 224 void VisitMember(Member* edge) override { might_be_collected_ = true; } 225 void VisitCollection(Collection* edge) override { 226 if (edge->on_heap()) { 227 might_be_collected_ = !edge->is_root(); 228 } else { 229 edge->AcceptMembers(this); 230 } 231 } 232 233 private: 234 bool might_be_collected_; 235 }; 236 237 public: 238 typedef std::vector<std::pair<MemberExpr*, FieldPoint*> > Errors; 239 240 CheckFinalizerVisitor(RecordCache* cache) 241 : blacklist_context_(false), cache_(cache) {} 242 243 Errors& finalized_fields() { return finalized_fields_; } 244 245 bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr* expr) { 246 // Only continue the walk-up if the operator is a blacklisted one. 247 switch (expr->getOperator()) { 248 case OO_Arrow: 249 case OO_Subscript: 250 this->WalkUpFromCallExpr(expr); 251 default: 252 return true; 253 } 254 } 255 256 // We consider all non-operator calls to be blacklisted contexts. 257 bool WalkUpFromCallExpr(CallExpr* expr) { 258 bool prev_blacklist_context = blacklist_context_; 259 blacklist_context_ = true; 260 for (size_t i = 0; i < expr->getNumArgs(); ++i) 261 this->TraverseStmt(expr->getArg(i)); 262 blacklist_context_ = prev_blacklist_context; 263 return true; 264 } 265 266 bool VisitMemberExpr(MemberExpr* member) { 267 FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()); 268 if (!field) 269 return true; 270 271 RecordInfo* info = cache_->Lookup(field->getParent()); 272 if (!info) 273 return true; 274 275 RecordInfo::Fields::iterator it = info->GetFields().find(field); 276 if (it == info->GetFields().end()) 277 return true; 278 279 if (blacklist_context_ && MightBeCollected(&it->second)) 280 finalized_fields_.push_back(std::make_pair(member, &it->second)); 281 return true; 282 } 283 284 bool MightBeCollected(FieldPoint* point) { 285 MightBeCollectedVisitor visitor; 286 point->edge()->Accept(&visitor); 287 return visitor.might_be_collected(); 288 } 289 290 private: 291 bool blacklist_context_; 292 Errors finalized_fields_; 293 RecordCache* cache_; 294 }; 295 296 // This visitor checks that a method contains within its body, a call to a 297 // method on the provided receiver class. This is used to check manual 298 // dispatching for trace and finalize methods. 299 class CheckDispatchVisitor : public RecursiveASTVisitor<CheckDispatchVisitor> { 300 public: 301 CheckDispatchVisitor(RecordInfo* receiver) 302 : receiver_(receiver), dispatched_to_receiver_(false) {} 303 304 bool dispatched_to_receiver() { return dispatched_to_receiver_; } 305 306 bool VisitMemberExpr(MemberExpr* member) { 307 if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) { 308 if (fn->getParent() == receiver_->record()) 309 dispatched_to_receiver_ = true; 310 } 311 return true; 312 } 313 314 private: 315 RecordInfo* receiver_; 316 bool dispatched_to_receiver_; 317 }; 318 319 // 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 base is traced if a base-qualified call to a trace method is found. 322 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { 323 public: 324 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) 325 : trace_(trace), info_(info) {} 326 327 bool VisitMemberExpr(MemberExpr* member) { 328 // In weak callbacks, consider any occurrence as a correct usage. 329 // TODO: We really want to require that isAlive is checked on manually 330 // processed weak fields. 331 if (IsWeakCallback()) { 332 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) 333 FoundField(field); 334 } 335 return true; 336 } 337 338 bool VisitCallExpr(CallExpr* call) { 339 // In weak callbacks we don't check calls (see VisitMemberExpr). 340 if (IsWeakCallback()) 341 return true; 342 343 Expr* callee = call->getCallee(); 344 345 // Trace calls from a templated derived class result in a 346 // DependentScopeMemberExpr because the concrete trace call depends on the 347 // instantiation of any shared template parameters. In this case the call is 348 // "unresolved" and we resort to comparing the syntactic type names. 349 if (CXXDependentScopeMemberExpr* expr = 350 dyn_cast<CXXDependentScopeMemberExpr>(callee)) { 351 CheckCXXDependentScopeMemberExpr(call, expr); 352 return true; 353 } 354 355 // A tracing call will have either a |visitor| or a |m_field| argument. 356 // A registerWeakMembers call will have a |this| argument. 357 if (call->getNumArgs() != 1) 358 return true; 359 Expr* arg = call->getArg(0); 360 361 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { 362 // If we find a call to registerWeakMembers which is unresolved we 363 // unsoundly consider all weak members as traced. 364 // TODO: Find out how to validate weak member tracing for unresolved call. 365 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { 366 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); 367 it != info_->GetFields().end(); 368 ++it) { 369 if (it->second.edge()->IsWeakMember()) 370 it->second.MarkTraced(); 371 } 372 } 373 374 QualType base = expr->getBaseType(); 375 if (!base->isPointerType()) 376 return true; 377 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); 378 if (decl) 379 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); 380 return true; 381 } 382 383 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { 384 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) 385 return true; 386 } 387 388 CheckTraceBaseCall(call); 389 return true; 390 } 391 392 private: 393 394 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { 395 NestedNameSpecifier* qual = expr->getQualifier(); 396 if (!qual) 397 return 0; 398 399 const Type* type = qual->getAsType(); 400 if (!type) 401 return 0; 402 403 const TemplateSpecializationType* tmpl_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 } 414 415 void CheckCXXDependentScopeMemberExpr(CallExpr* call, 416 CXXDependentScopeMemberExpr* expr) { 417 string fn_name = expr->getMember().getAsString(); 418 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); 419 if (!tmpl) 420 return; 421 422 // Check for Super<T>::trace(visitor) 423 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) { 424 RecordInfo::Bases::iterator it = info_->GetBases().begin(); 425 for (; it != info_->GetBases().end(); ++it) { 426 if (it->first->getName() == tmpl->getName()) 427 it->second.MarkTraced(); 428 } 429 return; 430 } 431 432 // Check for TraceIfNeeded<T>::trace(visitor, &field) 433 if (call->getNumArgs() == 2 && fn_name == kTraceName && 434 tmpl->getName() == kTraceIfNeededName) { 435 FindFieldVisitor finder; 436 finder.TraverseStmt(call->getArg(1)); 437 if (finder.field()) 438 FoundField(finder.field()); 439 } 440 } 441 442 bool CheckTraceBaseCall(CallExpr* call) { 443 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); 444 if (!callee) 445 return false; 446 447 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); 448 if (!fn || !Config::IsTraceMethod(fn)) 449 return false; 450 451 // Currently, a manually dispatched class cannot have mixin bases (having 452 // 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 454 // this if our mixin/vtable assumption changes. 455 if (fn->getName() != trace_->getName()) 456 return false; 457 458 CXXRecordDecl* decl = 0; 459 if (callee && callee->hasQualifier()) { 460 if (const Type* type = callee->getQualifier()->getAsType()) 461 decl = type->getAsCXXRecordDecl(); 462 } 463 if (!decl) 464 return false; 465 466 RecordInfo::Bases::iterator it = info_->GetBases().find(decl); 467 if (it != info_->GetBases().end()) { 468 it->second.MarkTraced(); 469 } 470 471 return true; 472 } 473 474 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { 475 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), 476 call->getRecordDecl(), 477 call->getArg(0)); 478 } 479 480 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { 481 if (name != kTraceName || !Config::IsVisitor(callee->getName())) 482 return false; 483 484 FindFieldVisitor finder; 485 finder.TraverseStmt(arg); 486 if (finder.field()) 487 FoundField(finder.field()); 488 489 return true; 490 } 491 492 bool CheckRegisterWeakMembers(CXXMemberCallExpr* call) { 493 CXXMethodDecl* fn = call->getMethodDecl(); 494 if (fn->getName() != kRegisterWeakMembersName) 495 return false; 496 497 if (fn->isTemplateInstantiation()) { 498 const TemplateArgumentList& args = 499 *fn->getTemplateSpecializationInfo()->TemplateArguments; 500 // The second template argument is the callback method. 501 if (args.size() > 1 && 502 args[1].getKind() == TemplateArgument::Declaration) { 503 if (FunctionDecl* callback = 504 dyn_cast<FunctionDecl>(args[1].getAsDecl())) { 505 if (callback->hasBody()) { 506 CheckTraceVisitor nested_visitor(info_); 507 nested_visitor.TraverseStmt(callback->getBody()); 508 } 509 } 510 } 511 } 512 return true; 513 } 514 515 class FindFieldVisitor : public RecursiveASTVisitor<FindFieldVisitor> { 516 public: 517 FindFieldVisitor() : member_(0), field_(0) {} 518 MemberExpr* member() const { return member_; } 519 FieldDecl* field() const { return field_; } 520 bool TraverseMemberExpr(MemberExpr* member) { 521 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) { 522 member_ = member; 523 field_ = field; 524 return false; 525 } 526 return true; 527 } 528 private: 529 MemberExpr* member_; 530 FieldDecl* field_; 531 }; 532 533 // Nested checking for weak callbacks. 534 CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} 535 536 bool IsWeakCallback() { return !trace_; } 537 538 void MarkTraced(RecordInfo::Fields::iterator it) { 539 // In a weak callback we can't mark strong fields as traced. 540 if (IsWeakCallback() && !it->second.edge()->IsWeakMember()) 541 return; 542 it->second.MarkTraced(); 543 } 544 545 void FoundField(FieldDecl* field) { 546 if (IsTemplateInstantiation(info_->record())) { 547 // Pointer equality on fields does not work for template instantiations. 548 // The trace method refers to fields of the template definition which 549 // are different from the instantiated fields that need to be traced. 550 const string& name = field->getNameAsString(); 551 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); 552 it != info_->GetFields().end(); 553 ++it) { 554 if (it->first->getNameAsString() == name) { 555 MarkTraced(it); 556 break; 557 } 558 } 559 } else { 560 RecordInfo::Fields::iterator it = info_->GetFields().find(field); 561 if (it != info_->GetFields().end()) 562 MarkTraced(it); 563 } 564 } 565 566 CXXMethodDecl* trace_; 567 RecordInfo* info_; 568 }; 569 570 // This visitor checks that the fields of a class and the fields of 571 // its part objects don't define GC roots. 572 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { 573 public: 574 typedef std::vector<FieldPoint*> RootPath; 575 typedef std::vector<RootPath> Errors; 576 577 CheckGCRootsVisitor() {} 578 579 Errors& gc_roots() { return gc_roots_; } 580 581 bool ContainsGCRoots(RecordInfo* info) { 582 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 583 it != info->GetFields().end(); 584 ++it) { 585 current_.push_back(&it->second); 586 it->second.edge()->Accept(this); 587 current_.pop_back(); 588 } 589 return !gc_roots_.empty(); 590 } 591 592 void VisitValue(Value* edge) override { 593 // TODO: what should we do to check unions? 594 if (edge->value()->record()->isUnion()) 595 return; 596 597 // If the value is a part object, then continue checking for roots. 598 for (Context::iterator it = context().begin(); 599 it != context().end(); 600 ++it) { 601 if (!(*it)->IsCollection()) 602 return; 603 } 604 ContainsGCRoots(edge->value()); 605 } 606 607 void VisitPersistent(Persistent* edge) override { 608 gc_roots_.push_back(current_); 609 } 610 611 void AtCollection(Collection* edge) override { 612 if (edge->is_root()) 613 gc_roots_.push_back(current_); 614 } 615 616 protected: 617 RootPath current_; 618 Errors gc_roots_; 619 }; 620 621 // This visitor checks that the fields of a class are "well formed". 622 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types. 623 // - Part objects must not be GC derived types. 624 // - An on-heap class must never contain GC roots. 625 // - Only stack-allocated types may point to stack-allocated types. 626 class CheckFieldsVisitor : public RecursiveEdgeVisitor { 627 public: 628 629 enum Error { 630 kRawPtrToGCManaged, 631 kRawPtrToGCManagedWarning, 632 kRefPtrToGCManaged, 633 kOwnPtrToGCManaged, 634 kMemberInUnmanaged, 635 kPtrFromHeapToStack, 636 kGCDerivedPartObject 637 }; 638 639 typedef std::vector<std::pair<FieldPoint*, Error> > Errors; 640 641 CheckFieldsVisitor(const BlinkGCPluginOptions& options) 642 : options_(options), current_(0), stack_allocated_host_(false) {} 643 644 Errors& invalid_fields() { return invalid_fields_; } 645 646 bool ContainsInvalidFields(RecordInfo* info) { 647 stack_allocated_host_ = info->IsStackAllocated(); 648 managed_host_ = stack_allocated_host_ || 649 info->IsGCAllocated() || 650 info->IsNonNewable() || 651 info->IsOnlyPlacementNewable(); 652 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 653 it != info->GetFields().end(); 654 ++it) { 655 context().clear(); 656 current_ = &it->second; 657 current_->edge()->Accept(this); 658 } 659 return !invalid_fields_.empty(); 660 } 661 662 void AtMember(Member* edge) override { 663 if (managed_host_) 664 return; 665 // A member is allowed to appear in the context of a root. 666 for (Context::iterator it = context().begin(); 667 it != context().end(); 668 ++it) { 669 if ((*it)->Kind() == Edge::kRoot) 670 return; 671 } 672 invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged)); 673 } 674 675 void AtValue(Value* edge) override { 676 // TODO: what should we do to check unions? 677 if (edge->value()->record()->isUnion()) 678 return; 679 680 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) { 681 invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack)); 682 return; 683 } 684 685 if (!Parent() && 686 edge->value()->IsGCDerived() && 687 !edge->value()->IsGCMixin()) { 688 invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject)); 689 return; 690 } 691 692 if (!Parent() || !edge->value()->IsGCAllocated()) 693 return; 694 695 // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's, 696 // also disallow T* in stack-allocated types. 697 if (options_.enable_oilpan) { 698 if (Parent()->IsOwnPtr() || 699 Parent()->IsRawPtrClass() || 700 (stack_allocated_host_ && Parent()->IsRawPtr())) { 701 invalid_fields_.push_back(std::make_pair( 702 current_, InvalidSmartPtr(Parent()))); 703 return; 704 } 705 if (options_.warn_raw_ptr && Parent()->IsRawPtr()) { 706 invalid_fields_.push_back(std::make_pair( 707 current_, kRawPtrToGCManagedWarning)); 708 } 709 return; 710 } 711 712 if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) { 713 invalid_fields_.push_back(std::make_pair( 714 current_, InvalidSmartPtr(Parent()))); 715 return; 716 } 717 } 718 719 void AtCollection(Collection* edge) override { 720 if (edge->on_heap() && Parent() && Parent()->IsOwnPtr()) 721 invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged)); 722 } 723 724 private: 725 Error InvalidSmartPtr(Edge* ptr) { 726 if (ptr->IsRawPtr()) 727 return kRawPtrToGCManaged; 728 if (ptr->IsRefPtr()) 729 return kRefPtrToGCManaged; 730 if (ptr->IsOwnPtr()) 731 return kOwnPtrToGCManaged; 732 assert(false && "Unknown smart pointer kind"); 733 } 734 735 const BlinkGCPluginOptions& options_; 736 FieldPoint* current_; 737 bool stack_allocated_host_; 738 bool managed_host_; 739 Errors invalid_fields_; 740 }; 741 742 class EmptyStmtVisitor 743 : public RecursiveASTVisitor<EmptyStmtVisitor> { 744 public: 745 static bool isEmpty(Stmt* stmt) { 746 EmptyStmtVisitor visitor; 747 visitor.TraverseStmt(stmt); 748 return visitor.empty_; 749 } 750 751 bool WalkUpFromCompoundStmt(CompoundStmt* stmt) { 752 empty_ = stmt->body_empty(); 753 return false; 754 } 755 bool VisitStmt(Stmt*) { 756 empty_ = false; 757 return false; 758 } 759 private: 760 EmptyStmtVisitor() : empty_(true) {} 761 bool empty_; 762 }; 763 764 // Main class containing checks for various invariants of the Blink 765 // garbage collection infrastructure. 766 class BlinkGCPluginConsumer : public ASTConsumer { 767 public: 768 BlinkGCPluginConsumer(CompilerInstance& instance, 769 const BlinkGCPluginOptions& options) 770 : instance_(instance), 771 diagnostic_(instance.getDiagnostics()), 772 options_(options), 773 json_(0) { 774 775 // Only check structures in the blink and WebKit namespaces. 776 options_.checked_namespaces.insert("blink"); 777 options_.checked_namespaces.insert("WebKit"); 778 779 // Ignore GC implementation files. 780 options_.ignored_directories.push_back("/heap/"); 781 782 // Register warning/error messages. 783 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID( 784 getErrorLevel(), kClassMustLeftMostlyDeriveGC); 785 diag_class_requires_trace_method_ = 786 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod); 787 diag_base_requires_tracing_ = 788 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing); 789 diag_fields_require_tracing_ = 790 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); 791 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID( 792 getErrorLevel(), kClassContainsInvalidFields); 793 diag_class_contains_invalid_fields_warning_ = diagnostic_.getCustomDiagID( 794 DiagnosticsEngine::Warning, kClassContainsInvalidFields); 795 diag_class_contains_gc_root_ = 796 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot); 797 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID( 798 getErrorLevel(), kClassRequiresFinalization); 799 diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID( 800 DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization); 801 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( 802 getErrorLevel(), kFinalizerAccessesFinalizedField); 803 diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID( 804 getErrorLevel(), kOverriddenNonVirtualTrace); 805 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID( 806 getErrorLevel(), kMissingTraceDispatchMethod); 807 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID( 808 getErrorLevel(), kMissingFinalizeDispatchMethod); 809 diag_virtual_and_manual_dispatch_ = 810 diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch); 811 diag_missing_trace_dispatch_ = 812 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch); 813 diag_missing_finalize_dispatch_ = 814 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch); 815 diag_derives_non_stack_allocated_ = 816 diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated); 817 diag_class_overrides_new_ = 818 diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew); 819 diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID( 820 getErrorLevel(), kClassDeclaresPureVirtualTrace); 821 diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID( 822 getErrorLevel(), kLeftMostBaseMustBePolymorphic); 823 diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID( 824 getErrorLevel(), kBaseClassMustDeclareVirtualTrace); 825 826 // Register note messages. 827 diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID( 828 DiagnosticsEngine::Note, kBaseRequiresTracingNote); 829 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( 830 DiagnosticsEngine::Note, kFieldRequiresTracingNote); 831 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 832 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); 833 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 834 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); 835 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 836 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); 837 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID( 838 DiagnosticsEngine::Note, kStackAllocatedFieldNote); 839 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID( 840 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote); 841 diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID( 842 DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote); 843 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( 844 DiagnosticsEngine::Note, kPartObjectContainsGCRootNote); 845 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( 846 DiagnosticsEngine::Note, kFieldContainsGCRootNote); 847 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( 848 DiagnosticsEngine::Note, kFinalizedFieldNote); 849 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( 850 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); 851 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( 852 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote); 853 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( 854 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); 855 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( 856 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); 857 diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID( 858 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); 859 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( 860 DiagnosticsEngine::Note, kManualDispatchMethodNote); 861 } 862 863 void HandleTranslationUnit(ASTContext& context) override { 864 CollectVisitor visitor; 865 visitor.TraverseDecl(context.getTranslationUnitDecl()); 866 867 if (options_.dump_graph) { 868 std::error_code err; 869 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work. 870 json_ = JsonWriter::from(instance_.createOutputFile( 871 "", // OutputPath 872 err, // Errors 873 true, // Binary 874 true, // RemoveFileOnSignal 875 instance_.getFrontendOpts().OutputFile, // BaseInput 876 "graph.json", // Extension 877 false, // UseTemporary 878 false, // CreateMissingDirectories 879 0, // ResultPathName 880 0)); // TempPathName 881 if (!err && json_) { 882 json_->OpenList(); 883 } else { 884 json_ = 0; 885 llvm::errs() 886 << "[blink-gc] " 887 << "Failed to create an output file for the object graph.\n"; 888 } 889 } 890 891 for (RecordVector::iterator it = visitor.record_decls().begin(); 892 it != visitor.record_decls().end(); 893 ++it) { 894 CheckRecord(cache_.Lookup(*it)); 895 } 896 897 for (MethodVector::iterator it = visitor.trace_decls().begin(); 898 it != visitor.trace_decls().end(); 899 ++it) { 900 CheckTracingMethod(*it); 901 } 902 903 if (json_) { 904 json_->CloseList(); 905 delete json_; 906 json_ = 0; 907 } 908 } 909 910 // Main entry for checking a record declaration. 911 void CheckRecord(RecordInfo* info) { 912 if (IsIgnored(info)) 913 return; 914 915 CXXRecordDecl* record = info->record(); 916 917 // TODO: what should we do to check unions? 918 if (record->isUnion()) 919 return; 920 921 // If this is the primary template declaration, check its specializations. 922 if (record->isThisDeclarationADefinition() && 923 record->getDescribedClassTemplate()) { 924 ClassTemplateDecl* tmpl = record->getDescribedClassTemplate(); 925 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin(); 926 it != tmpl->spec_end(); 927 ++it) { 928 CheckClass(cache_.Lookup(*it)); 929 } 930 return; 931 } 932 933 CheckClass(info); 934 } 935 936 // Check a class-like object (eg, class, specialization, instantiation). 937 void CheckClass(RecordInfo* info) { 938 if (!info) 939 return; 940 941 // Check consistency of stack-allocated hierarchies. 942 if (info->IsStackAllocated()) { 943 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); 944 it != info->GetBases().end(); 945 ++it) { 946 if (!it->second.info()->IsStackAllocated()) 947 ReportDerivesNonStackAllocated(info, &it->second); 948 } 949 } 950 951 if (CXXMethodDecl* trace = info->GetTraceMethod()) { 952 if (trace->isPure()) 953 ReportClassDeclaresPureVirtualTrace(info, trace); 954 } else if (info->RequiresTraceMethod()) { 955 ReportClassRequiresTraceMethod(info); 956 } 957 958 // Check polymorphic classes that are GC-derived or have a trace method. 959 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) { 960 CXXMethodDecl* trace = info->GetTraceMethod(); 961 if (trace || info->IsGCDerived()) 962 CheckPolymorphicClass(info, trace); 963 } 964 965 { 966 CheckFieldsVisitor visitor(options_); 967 if (visitor.ContainsInvalidFields(info)) 968 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); 969 } 970 971 if (info->IsGCDerived()) { 972 973 if (!info->IsGCMixin()) { 974 CheckLeftMostDerived(info); 975 CheckDispatch(info); 976 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) 977 ReportClassOverridesNew(info, newop); 978 } 979 980 { 981 CheckGCRootsVisitor visitor; 982 if (visitor.ContainsGCRoots(info)) 983 ReportClassContainsGCRoots(info, &visitor.gc_roots()); 984 } 985 986 if (info->NeedsFinalization()) 987 CheckFinalization(info); 988 989 if (options_.warn_unneeded_finalizer && info->IsGCFinalized()) 990 CheckUnneededFinalization(info); 991 } 992 993 DumpClass(info); 994 } 995 996 CXXRecordDecl* GetDependentTemplatedDecl(const Type& type) { 997 const TemplateSpecializationType* tmpl_type = 998 type.getAs<TemplateSpecializationType>(); 999 if (!tmpl_type) 1000 return 0; 1001 1002 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); 1003 if (!tmpl_decl) 1004 return 0; 1005 1006 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); 1007 } 1008 1009 // The GC infrastructure assumes that if the vtable of a polymorphic 1010 // base-class is not initialized for a given object (ie, it is partially 1011 // initialized) then the object does not need to be traced. Thus, we must 1012 // ensure that any polymorphic class with a trace method does not have any 1013 // tractable fields that are initialized before we are sure that the vtable 1014 // and the trace method are both defined. There are two cases that need to 1015 // hold to satisfy that assumption: 1016 // 1017 // 1. If trace is virtual, then it must be defined in the left-most base. 1018 // This ensures that if the vtable is initialized then it contains a pointer 1019 // to the trace method. 1020 // 1021 // 2. If trace is non-virtual, then the trace method is defined and we must 1022 // ensure that the left-most base defines a vtable. This ensures that the 1023 // first thing to be initialized when constructing the object is the vtable 1024 // itself. 1025 void CheckPolymorphicClass(RecordInfo* info, CXXMethodDecl* trace) { 1026 CXXRecordDecl* left_most = info->record(); 1027 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1028 CXXRecordDecl* left_most_base = 0; 1029 while (it != left_most->bases_end()) { 1030 left_most_base = it->getType()->getAsCXXRecordDecl(); 1031 if (!left_most_base && it->getType()->isDependentType()) 1032 left_most_base = GetDependentTemplatedDecl(*it->getType()); 1033 1034 // TODO: Find a way to correctly check actual instantiations 1035 // for dependent types. The escape below will be hit, eg, when 1036 // we have a primary template with no definition and 1037 // specializations for each case (such as SupplementBase) in 1038 // which case we don't succeed in checking the required 1039 // properties. 1040 if (!left_most_base || !left_most_base->hasDefinition()) 1041 return; 1042 1043 StringRef name = left_most_base->getName(); 1044 // We know GCMixin base defines virtual trace. 1045 if (Config::IsGCMixinBase(name)) 1046 return; 1047 1048 // Stop with the left-most prior to a safe polymorphic base (a safe base 1049 // is non-polymorphic and contains no fields). 1050 if (Config::IsSafePolymorphicBase(name)) 1051 break; 1052 1053 left_most = left_most_base; 1054 it = left_most->bases_begin(); 1055 } 1056 1057 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { 1058 1059 // Check condition (1): 1060 if (trace && trace->isVirtual()) { 1061 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { 1062 if (trace->isVirtual()) 1063 return; 1064 } 1065 ReportBaseClassMustDeclareVirtualTrace(info, left_most); 1066 return; 1067 } 1068 1069 // Check condition (2): 1070 if (DeclaresVirtualMethods(left_most)) 1071 return; 1072 if (left_most_base) { 1073 ++it; // Get the base next to the "safe polymorphic base" 1074 if (it != left_most->bases_end()) { 1075 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { 1076 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { 1077 if (DeclaresVirtualMethods(next_left_most)) 1078 return; 1079 ReportLeftMostBaseMustBePolymorphic(info, next_left_most); 1080 return; 1081 } 1082 } 1083 } 1084 } 1085 ReportLeftMostBaseMustBePolymorphic(info, left_most); 1086 } 1087 } 1088 1089 CXXRecordDecl* GetLeftMostBase(CXXRecordDecl* left_most) { 1090 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1091 while (it != left_most->bases_end()) { 1092 if (it->getType()->isDependentType()) 1093 left_most = GetDependentTemplatedDecl(*it->getType()); 1094 else 1095 left_most = it->getType()->getAsCXXRecordDecl(); 1096 if (!left_most || !left_most->hasDefinition()) 1097 return 0; 1098 it = left_most->bases_begin(); 1099 } 1100 return left_most; 1101 } 1102 1103 bool DeclaresVirtualMethods(CXXRecordDecl* decl) { 1104 CXXRecordDecl::method_iterator it = decl->method_begin(); 1105 for (; it != decl->method_end(); ++it) 1106 if (it->isVirtual() && !it->isPure()) 1107 return true; 1108 return false; 1109 } 1110 1111 void CheckLeftMostDerived(RecordInfo* info) { 1112 CXXRecordDecl* left_most = info->record(); 1113 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); 1114 while (it != left_most->bases_end()) { 1115 left_most = it->getType()->getAsCXXRecordDecl(); 1116 it = left_most->bases_begin(); 1117 } 1118 if (!Config::IsGCBase(left_most->getName())) 1119 ReportClassMustLeftMostlyDeriveGC(info); 1120 } 1121 1122 void CheckDispatch(RecordInfo* info) { 1123 bool finalized = info->IsGCFinalized(); 1124 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod(); 1125 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod(); 1126 if (!trace_dispatch && !finalize_dispatch) 1127 return; 1128 1129 CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent() 1130 : finalize_dispatch->getParent(); 1131 1132 // Check that dispatch methods are defined at the base. 1133 if (base == info->record()) { 1134 if (!trace_dispatch) 1135 ReportMissingTraceDispatchMethod(info); 1136 if (finalized && !finalize_dispatch) 1137 ReportMissingFinalizeDispatchMethod(info); 1138 if (!finalized && finalize_dispatch) { 1139 ReportClassRequiresFinalization(info); 1140 NoteUserDeclaredFinalizer(finalize_dispatch); 1141 } 1142 } 1143 1144 // Check that classes implementing manual dispatch do not have vtables. 1145 if (info->record()->isPolymorphic()) 1146 ReportVirtualAndManualDispatch( 1147 info, trace_dispatch ? trace_dispatch : finalize_dispatch); 1148 1149 // If this is a non-abstract class check that it is dispatched to. 1150 // TODO: Create a global variant of this local check. We can only check if 1151 // the dispatch body is known in this compilation unit. 1152 if (info->IsConsideredAbstract()) 1153 return; 1154 1155 const FunctionDecl* defn; 1156 1157 if (trace_dispatch && trace_dispatch->isDefined(defn)) { 1158 CheckDispatchVisitor visitor(info); 1159 visitor.TraverseStmt(defn->getBody()); 1160 if (!visitor.dispatched_to_receiver()) 1161 ReportMissingTraceDispatch(defn, info); 1162 } 1163 1164 if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) { 1165 CheckDispatchVisitor visitor(info); 1166 visitor.TraverseStmt(defn->getBody()); 1167 if (!visitor.dispatched_to_receiver()) 1168 ReportMissingFinalizeDispatch(defn, info); 1169 } 1170 } 1171 1172 // TODO: Should we collect destructors similar to trace methods? 1173 void CheckFinalization(RecordInfo* info) { 1174 CXXDestructorDecl* dtor = info->record()->getDestructor(); 1175 1176 // For finalized classes, check the finalization method if possible. 1177 if (info->IsGCFinalized()) { 1178 if (dtor && dtor->hasBody()) { 1179 CheckFinalizerVisitor visitor(&cache_); 1180 visitor.TraverseCXXMethodDecl(dtor); 1181 if (!visitor.finalized_fields().empty()) { 1182 ReportFinalizerAccessesFinalizedFields( 1183 dtor, &visitor.finalized_fields()); 1184 } 1185 } 1186 return; 1187 } 1188 1189 // Don't require finalization of a mixin that has not yet been "mixed in". 1190 if (info->IsGCMixin()) 1191 return; 1192 1193 // Report the finalization error, and proceed to print possible causes for 1194 // the finalization requirement. 1195 ReportClassRequiresFinalization(info); 1196 1197 if (dtor && dtor->isUserProvided()) 1198 NoteUserDeclaredDestructor(dtor); 1199 1200 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); 1201 it != info->GetBases().end(); 1202 ++it) { 1203 if (it->second.info()->NeedsFinalization()) 1204 NoteBaseRequiresFinalization(&it->second); 1205 } 1206 1207 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 1208 it != info->GetFields().end(); 1209 ++it) { 1210 if (it->second.edge()->NeedsFinalization()) 1211 NoteField(&it->second, diag_field_requires_finalization_note_); 1212 } 1213 } 1214 1215 void CheckUnneededFinalization(RecordInfo* info) { 1216 if (!HasNonEmptyFinalizer(info)) 1217 ReportClassDoesNotRequireFinalization(info); 1218 } 1219 1220 bool HasNonEmptyFinalizer(RecordInfo* info) { 1221 CXXDestructorDecl* dtor = info->record()->getDestructor(); 1222 if (dtor && dtor->isUserProvided()) { 1223 if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody())) 1224 return true; 1225 } 1226 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); 1227 it != info->GetBases().end(); 1228 ++it) { 1229 if (HasNonEmptyFinalizer(it->second.info())) 1230 return true; 1231 } 1232 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 1233 it != info->GetFields().end(); 1234 ++it) { 1235 if (it->second.edge()->NeedsFinalization()) 1236 return true; 1237 } 1238 return false; 1239 } 1240 1241 // This is the main entry for tracing method definitions. 1242 void CheckTracingMethod(CXXMethodDecl* method) { 1243 RecordInfo* parent = cache_.Lookup(method->getParent()); 1244 if (IsIgnored(parent)) 1245 return; 1246 1247 // Check templated tracing methods by checking the template instantiations. 1248 // Specialized templates are handled as ordinary classes. 1249 if (ClassTemplateDecl* tmpl = 1250 parent->record()->getDescribedClassTemplate()) { 1251 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin(); 1252 it != tmpl->spec_end(); 1253 ++it) { 1254 // Check trace using each template instantiation as the holder. 1255 if (IsTemplateInstantiation(*it)) 1256 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method); 1257 } 1258 return; 1259 } 1260 1261 CheckTraceOrDispatchMethod(parent, method); 1262 } 1263 1264 // Determine what type of tracing method this is (dispatch or trace). 1265 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { 1266 bool isTraceAfterDispatch; 1267 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) { 1268 if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) { 1269 CheckTraceMethod(parent, method, isTraceAfterDispatch); 1270 } 1271 // Dispatch methods are checked when we identify subclasses. 1272 } 1273 } 1274 1275 // Check an actual trace method. 1276 void CheckTraceMethod(RecordInfo* parent, 1277 CXXMethodDecl* trace, 1278 bool isTraceAfterDispatch) { 1279 // A trace method must not override any non-virtual trace methods. 1280 if (!isTraceAfterDispatch) { 1281 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1282 it != parent->GetBases().end(); 1283 ++it) { 1284 RecordInfo* base = it->second.info(); 1285 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) 1286 ReportOverriddenNonVirtualTrace(parent, trace, other); 1287 } 1288 } 1289 1290 CheckTraceVisitor visitor(trace, parent); 1291 visitor.TraverseCXXMethodDecl(trace); 1292 1293 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1294 it != parent->GetBases().end(); 1295 ++it) { 1296 if (!it->second.IsProperlyTraced()) 1297 ReportBaseRequiresTracing(parent, trace, it->first); 1298 } 1299 1300 for (RecordInfo::Fields::iterator it = parent->GetFields().begin(); 1301 it != parent->GetFields().end(); 1302 ++it) { 1303 if (!it->second.IsProperlyTraced()) { 1304 // Discontinue once an untraced-field error is found. 1305 ReportFieldsRequireTracing(parent, trace); 1306 break; 1307 } 1308 } 1309 } 1310 1311 void DumpClass(RecordInfo* info) { 1312 if (!json_) 1313 return; 1314 1315 json_->OpenObject(); 1316 json_->Write("name", info->record()->getQualifiedNameAsString()); 1317 json_->Write("loc", GetLocString(info->record()->getLocStart())); 1318 json_->CloseObject(); 1319 1320 class DumpEdgeVisitor : public RecursiveEdgeVisitor { 1321 public: 1322 DumpEdgeVisitor(JsonWriter* json) : json_(json) {} 1323 void DumpEdge(RecordInfo* src, 1324 RecordInfo* dst, 1325 const string& lbl, 1326 const Edge::LivenessKind& kind, 1327 const string& loc) { 1328 json_->OpenObject(); 1329 json_->Write("src", src->record()->getQualifiedNameAsString()); 1330 json_->Write("dst", dst->record()->getQualifiedNameAsString()); 1331 json_->Write("lbl", lbl); 1332 json_->Write("kind", kind); 1333 json_->Write("loc", loc); 1334 json_->Write("ptr", 1335 !Parent() ? "val" : 1336 Parent()->IsRawPtr() ? "raw" : 1337 Parent()->IsRefPtr() ? "ref" : 1338 Parent()->IsOwnPtr() ? "own" : 1339 (Parent()->IsMember() || 1340 Parent()->IsWeakMember()) ? "mem" : 1341 "val"); 1342 json_->CloseObject(); 1343 } 1344 1345 void DumpField(RecordInfo* src, FieldPoint* point, const string& loc) { 1346 src_ = src; 1347 point_ = point; 1348 loc_ = loc; 1349 point_->edge()->Accept(this); 1350 } 1351 1352 void AtValue(Value* e) override { 1353 // The liveness kind of a path from the point to this value 1354 // is given by the innermost place that is non-strong. 1355 Edge::LivenessKind kind = Edge::kStrong; 1356 if (Config::IsIgnoreCycleAnnotated(point_->field())) { 1357 kind = Edge::kWeak; 1358 } else { 1359 for (Context::iterator it = context().begin(); 1360 it != context().end(); 1361 ++it) { 1362 Edge::LivenessKind pointer_kind = (*it)->Kind(); 1363 if (pointer_kind != Edge::kStrong) { 1364 kind = pointer_kind; 1365 break; 1366 } 1367 } 1368 } 1369 DumpEdge( 1370 src_, e->value(), point_->field()->getNameAsString(), kind, loc_); 1371 } 1372 1373 private: 1374 JsonWriter* json_; 1375 RecordInfo* src_; 1376 FieldPoint* point_; 1377 string loc_; 1378 }; 1379 1380 DumpEdgeVisitor visitor(json_); 1381 1382 RecordInfo::Bases& bases = info->GetBases(); 1383 for (RecordInfo::Bases::iterator it = bases.begin(); 1384 it != bases.end(); 1385 ++it) { 1386 visitor.DumpEdge(info, 1387 it->second.info(), 1388 "<super>", 1389 Edge::kStrong, 1390 GetLocString(it->second.spec().getLocStart())); 1391 } 1392 1393 RecordInfo::Fields& fields = info->GetFields(); 1394 for (RecordInfo::Fields::iterator it = fields.begin(); 1395 it != fields.end(); 1396 ++it) { 1397 visitor.DumpField(info, 1398 &it->second, 1399 GetLocString(it->second.field()->getLocStart())); 1400 } 1401 } 1402 1403 // Adds either a warning or error, based on the current handling of -Werror. 1404 DiagnosticsEngine::Level getErrorLevel() { 1405 return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error 1406 : DiagnosticsEngine::Warning; 1407 } 1408 1409 const string GetLocString(SourceLocation loc) { 1410 const SourceManager& source_manager = instance_.getSourceManager(); 1411 PresumedLoc ploc = source_manager.getPresumedLoc(loc); 1412 if (ploc.isInvalid()) 1413 return ""; 1414 string loc_str; 1415 llvm::raw_string_ostream OS(loc_str); 1416 OS << ploc.getFilename() 1417 << ":" << ploc.getLine() 1418 << ":" << ploc.getColumn(); 1419 return OS.str(); 1420 } 1421 1422 bool IsIgnored(RecordInfo* record) { 1423 return !record || 1424 !InCheckedNamespace(record) || 1425 IsIgnoredClass(record) || 1426 InIgnoredDirectory(record); 1427 } 1428 1429 bool IsIgnoredClass(RecordInfo* info) { 1430 // Ignore any class prefixed by SameSizeAs. These are used in 1431 // Blink to verify class sizes and don't need checking. 1432 const string SameSizeAs = "SameSizeAs"; 1433 if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0) 1434 return true; 1435 return options_.ignored_classes.find(info->name()) != 1436 options_.ignored_classes.end(); 1437 } 1438 1439 bool InIgnoredDirectory(RecordInfo* info) { 1440 string filename; 1441 if (!GetFilename(info->record()->getLocStart(), &filename)) 1442 return false; // TODO: should we ignore non-existing file locations? 1443 std::vector<string>::iterator it = options_.ignored_directories.begin(); 1444 for (; it != options_.ignored_directories.end(); ++it) 1445 if (filename.find(*it) != string::npos) 1446 return true; 1447 return false; 1448 } 1449 1450 bool InCheckedNamespace(RecordInfo* info) { 1451 if (!info) 1452 return false; 1453 for (DeclContext* context = info->record()->getDeclContext(); 1454 !context->isTranslationUnit(); 1455 context = context->getParent()) { 1456 if (NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context)) { 1457 if (options_.checked_namespaces.find(decl->getNameAsString()) != 1458 options_.checked_namespaces.end()) { 1459 return true; 1460 } 1461 } 1462 } 1463 return false; 1464 } 1465 1466 bool GetFilename(SourceLocation loc, string* filename) { 1467 const SourceManager& source_manager = instance_.getSourceManager(); 1468 SourceLocation spelling_location = source_manager.getSpellingLoc(loc); 1469 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); 1470 if (ploc.isInvalid()) { 1471 // If we're in an invalid location, we're looking at things that aren't 1472 // actually stated in the source. 1473 return false; 1474 } 1475 *filename = ploc.getFilename(); 1476 return true; 1477 } 1478 1479 void ReportClassMustLeftMostlyDeriveGC(RecordInfo* info) { 1480 SourceLocation loc = info->record()->getInnerLocStart(); 1481 SourceManager& manager = instance_.getSourceManager(); 1482 FullSourceLoc full_loc(loc, manager); 1483 diagnostic_.Report(full_loc, diag_class_must_left_mostly_derive_gc_) 1484 << info->record(); 1485 } 1486 1487 void ReportClassRequiresTraceMethod(RecordInfo* info) { 1488 SourceLocation loc = info->record()->getInnerLocStart(); 1489 SourceManager& manager = instance_.getSourceManager(); 1490 FullSourceLoc full_loc(loc, manager); 1491 diagnostic_.Report(full_loc, diag_class_requires_trace_method_) 1492 << info->record(); 1493 1494 for (RecordInfo::Bases::iterator it = info->GetBases().begin(); 1495 it != info->GetBases().end(); 1496 ++it) { 1497 if (it->second.NeedsTracing().IsNeeded()) 1498 NoteBaseRequiresTracing(&it->second); 1499 } 1500 1501 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 1502 it != info->GetFields().end(); 1503 ++it) { 1504 if (!it->second.IsProperlyTraced()) 1505 NoteFieldRequiresTracing(info, it->first); 1506 } 1507 } 1508 1509 void ReportBaseRequiresTracing(RecordInfo* derived, 1510 CXXMethodDecl* trace, 1511 CXXRecordDecl* base) { 1512 SourceLocation loc = trace->getLocStart(); 1513 SourceManager& manager = instance_.getSourceManager(); 1514 FullSourceLoc full_loc(loc, manager); 1515 diagnostic_.Report(full_loc, diag_base_requires_tracing_) 1516 << base << derived->record(); 1517 } 1518 1519 void ReportFieldsRequireTracing(RecordInfo* info, CXXMethodDecl* trace) { 1520 SourceLocation loc = trace->getLocStart(); 1521 SourceManager& manager = instance_.getSourceManager(); 1522 FullSourceLoc full_loc(loc, manager); 1523 diagnostic_.Report(full_loc, diag_fields_require_tracing_) 1524 << info->record(); 1525 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 1526 it != info->GetFields().end(); 1527 ++it) { 1528 if (!it->second.IsProperlyTraced()) 1529 NoteFieldRequiresTracing(info, it->first); 1530 } 1531 } 1532 1533 void ReportClassContainsInvalidFields(RecordInfo* info, 1534 CheckFieldsVisitor::Errors* errors) { 1535 SourceLocation loc = info->record()->getLocStart(); 1536 SourceManager& manager = instance_.getSourceManager(); 1537 FullSourceLoc full_loc(loc, manager); 1538 bool only_warnings = options_.warn_raw_ptr; 1539 for (CheckFieldsVisitor::Errors::iterator it = errors->begin(); 1540 only_warnings && it != errors->end(); 1541 ++it) { 1542 if (it->second != CheckFieldsVisitor::kRawPtrToGCManagedWarning) 1543 only_warnings = false; 1544 } 1545 diagnostic_.Report(full_loc, only_warnings ? 1546 diag_class_contains_invalid_fields_warning_ : 1547 diag_class_contains_invalid_fields_) 1548 << info->record(); 1549 for (CheckFieldsVisitor::Errors::iterator it = errors->begin(); 1550 it != errors->end(); 1551 ++it) { 1552 unsigned error; 1553 if (it->second == CheckFieldsVisitor::kRawPtrToGCManaged || 1554 it->second == CheckFieldsVisitor::kRawPtrToGCManagedWarning) { 1555 error = diag_raw_ptr_to_gc_managed_class_note_; 1556 } else if (it->second == CheckFieldsVisitor::kRefPtrToGCManaged) { 1557 error = diag_ref_ptr_to_gc_managed_class_note_; 1558 } else if (it->second == CheckFieldsVisitor::kOwnPtrToGCManaged) { 1559 error = diag_own_ptr_to_gc_managed_class_note_; 1560 } else if (it->second == CheckFieldsVisitor::kMemberInUnmanaged) { 1561 error = diag_member_in_unmanaged_class_note_; 1562 } else if (it->second == CheckFieldsVisitor::kPtrFromHeapToStack) { 1563 error = diag_stack_allocated_field_note_; 1564 } else if (it->second == CheckFieldsVisitor::kGCDerivedPartObject) { 1565 error = diag_part_object_to_gc_derived_class_note_; 1566 } else { 1567 assert(false && "Unknown field error"); 1568 } 1569 NoteField(it->first, error); 1570 } 1571 } 1572 1573 void ReportClassContainsGCRoots(RecordInfo* info, 1574 CheckGCRootsVisitor::Errors* errors) { 1575 SourceLocation loc = info->record()->getLocStart(); 1576 SourceManager& manager = instance_.getSourceManager(); 1577 FullSourceLoc full_loc(loc, manager); 1578 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin(); 1579 it != errors->end(); 1580 ++it) { 1581 CheckGCRootsVisitor::RootPath::iterator path = it->begin(); 1582 FieldPoint* point = *path; 1583 diagnostic_.Report(full_loc, diag_class_contains_gc_root_) 1584 << info->record() << point->field(); 1585 while (++path != it->end()) { 1586 NotePartObjectContainsGCRoot(point); 1587 point = *path; 1588 } 1589 NoteFieldContainsGCRoot(point); 1590 } 1591 } 1592 1593 void ReportFinalizerAccessesFinalizedFields( 1594 CXXMethodDecl* dtor, 1595 CheckFinalizerVisitor::Errors* fields) { 1596 for (CheckFinalizerVisitor::Errors::iterator it = fields->begin(); 1597 it != fields->end(); 1598 ++it) { 1599 SourceLocation loc = it->first->getLocStart(); 1600 SourceManager& manager = instance_.getSourceManager(); 1601 FullSourceLoc full_loc(loc, manager); 1602 diagnostic_.Report(full_loc, diag_finalizer_accesses_finalized_field_) 1603 << dtor << it->second->field(); 1604 NoteField(it->second, diag_finalized_field_note_); 1605 } 1606 } 1607 1608 void ReportClassRequiresFinalization(RecordInfo* info) { 1609 SourceLocation loc = info->record()->getInnerLocStart(); 1610 SourceManager& manager = instance_.getSourceManager(); 1611 FullSourceLoc full_loc(loc, manager); 1612 diagnostic_.Report(full_loc, diag_class_requires_finalization_) 1613 << info->record(); 1614 } 1615 1616 void ReportClassDoesNotRequireFinalization(RecordInfo* info) { 1617 SourceLocation loc = info->record()->getInnerLocStart(); 1618 SourceManager& manager = instance_.getSourceManager(); 1619 FullSourceLoc full_loc(loc, manager); 1620 diagnostic_.Report(full_loc, diag_class_does_not_require_finalization_) 1621 << info->record(); 1622 } 1623 1624 void ReportOverriddenNonVirtualTrace(RecordInfo* info, 1625 CXXMethodDecl* trace, 1626 CXXMethodDecl* overridden) { 1627 SourceLocation loc = trace->getLocStart(); 1628 SourceManager& manager = instance_.getSourceManager(); 1629 FullSourceLoc full_loc(loc, manager); 1630 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_) 1631 << info->record() << overridden->getParent(); 1632 NoteOverriddenNonVirtualTrace(overridden); 1633 } 1634 1635 void ReportMissingTraceDispatchMethod(RecordInfo* info) { 1636 ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_); 1637 } 1638 1639 void ReportMissingFinalizeDispatchMethod(RecordInfo* info) { 1640 ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_); 1641 } 1642 1643 void ReportMissingDispatchMethod(RecordInfo* info, unsigned error) { 1644 SourceLocation loc = info->record()->getInnerLocStart(); 1645 SourceManager& manager = instance_.getSourceManager(); 1646 FullSourceLoc full_loc(loc, manager); 1647 diagnostic_.Report(full_loc, error) << info->record(); 1648 } 1649 1650 void ReportVirtualAndManualDispatch(RecordInfo* info, 1651 CXXMethodDecl* dispatch) { 1652 SourceLocation loc = info->record()->getInnerLocStart(); 1653 SourceManager& manager = instance_.getSourceManager(); 1654 FullSourceLoc full_loc(loc, manager); 1655 diagnostic_.Report(full_loc, diag_virtual_and_manual_dispatch_) 1656 << info->record(); 1657 NoteManualDispatchMethod(dispatch); 1658 } 1659 1660 void ReportMissingTraceDispatch(const FunctionDecl* dispatch, 1661 RecordInfo* receiver) { 1662 ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_); 1663 } 1664 1665 void ReportMissingFinalizeDispatch(const FunctionDecl* dispatch, 1666 RecordInfo* receiver) { 1667 ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_); 1668 } 1669 1670 void ReportMissingDispatch(const FunctionDecl* dispatch, 1671 RecordInfo* receiver, 1672 unsigned error) { 1673 SourceLocation loc = dispatch->getLocStart(); 1674 SourceManager& manager = instance_.getSourceManager(); 1675 FullSourceLoc full_loc(loc, manager); 1676 diagnostic_.Report(full_loc, error) << receiver->record(); 1677 } 1678 1679 void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base) { 1680 SourceLocation loc = base->spec().getLocStart(); 1681 SourceManager& manager = instance_.getSourceManager(); 1682 FullSourceLoc full_loc(loc, manager); 1683 diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_) 1684 << info->record() << base->info()->record(); 1685 } 1686 1687 void ReportClassOverridesNew(RecordInfo* info, CXXMethodDecl* newop) { 1688 SourceLocation loc = newop->getLocStart(); 1689 SourceManager& manager = instance_.getSourceManager(); 1690 FullSourceLoc full_loc(loc, manager); 1691 diagnostic_.Report(full_loc, diag_class_overrides_new_) << info->record(); 1692 } 1693 1694 void ReportClassDeclaresPureVirtualTrace(RecordInfo* info, 1695 CXXMethodDecl* trace) { 1696 SourceLocation loc = trace->getLocStart(); 1697 SourceManager& manager = instance_.getSourceManager(); 1698 FullSourceLoc full_loc(loc, manager); 1699 diagnostic_.Report(full_loc, diag_class_declares_pure_virtual_trace_) 1700 << info->record(); 1701 } 1702 1703 void ReportLeftMostBaseMustBePolymorphic(RecordInfo* derived, 1704 CXXRecordDecl* base) { 1705 SourceLocation loc = base->getLocStart(); 1706 SourceManager& manager = instance_.getSourceManager(); 1707 FullSourceLoc full_loc(loc, manager); 1708 diagnostic_.Report(full_loc, diag_left_most_base_must_be_polymorphic_) 1709 << base << derived->record(); 1710 } 1711 1712 void ReportBaseClassMustDeclareVirtualTrace(RecordInfo* derived, 1713 CXXRecordDecl* base) { 1714 SourceLocation loc = base->getLocStart(); 1715 SourceManager& manager = instance_.getSourceManager(); 1716 FullSourceLoc full_loc(loc, manager); 1717 diagnostic_.Report(full_loc, diag_base_class_must_declare_virtual_trace_) 1718 << base << derived->record(); 1719 } 1720 1721 void NoteManualDispatchMethod(CXXMethodDecl* dispatch) { 1722 SourceLocation loc = dispatch->getLocStart(); 1723 SourceManager& manager = instance_.getSourceManager(); 1724 FullSourceLoc full_loc(loc, manager); 1725 diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch; 1726 } 1727 1728 void NoteBaseRequiresTracing(BasePoint* base) { 1729 SourceLocation loc = base->spec().getLocStart(); 1730 SourceManager& manager = instance_.getSourceManager(); 1731 FullSourceLoc full_loc(loc, manager); 1732 diagnostic_.Report(full_loc, diag_base_requires_tracing_note_) 1733 << base->info()->record(); 1734 } 1735 1736 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { 1737 NoteField(field, diag_field_requires_tracing_note_); 1738 } 1739 1740 void NotePartObjectContainsGCRoot(FieldPoint* point) { 1741 FieldDecl* field = point->field(); 1742 SourceLocation loc = field->getLocStart(); 1743 SourceManager& manager = instance_.getSourceManager(); 1744 FullSourceLoc full_loc(loc, manager); 1745 diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_) 1746 << field << field->getParent(); 1747 } 1748 1749 void NoteFieldContainsGCRoot(FieldPoint* point) { 1750 NoteField(point, diag_field_contains_gc_root_note_); 1751 } 1752 1753 void NoteUserDeclaredDestructor(CXXMethodDecl* dtor) { 1754 SourceLocation loc = dtor->getLocStart(); 1755 SourceManager& manager = instance_.getSourceManager(); 1756 FullSourceLoc full_loc(loc, manager); 1757 diagnostic_.Report(full_loc, diag_user_declared_destructor_note_); 1758 } 1759 1760 void NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) { 1761 SourceLocation loc = dtor->getLocStart(); 1762 SourceManager& manager = instance_.getSourceManager(); 1763 FullSourceLoc full_loc(loc, manager); 1764 diagnostic_.Report(full_loc, diag_user_declared_finalizer_note_); 1765 } 1766 1767 void NoteBaseRequiresFinalization(BasePoint* base) { 1768 SourceLocation loc = base->spec().getLocStart(); 1769 SourceManager& manager = instance_.getSourceManager(); 1770 FullSourceLoc full_loc(loc, manager); 1771 diagnostic_.Report(full_loc, diag_base_requires_finalization_note_) 1772 << base->info()->record(); 1773 } 1774 1775 void NoteField(FieldPoint* point, unsigned note) { 1776 NoteField(point->field(), note); 1777 } 1778 1779 void NoteField(FieldDecl* field, unsigned note) { 1780 SourceLocation loc = field->getLocStart(); 1781 SourceManager& manager = instance_.getSourceManager(); 1782 FullSourceLoc full_loc(loc, manager); 1783 diagnostic_.Report(full_loc, note) << field; 1784 } 1785 1786 void NoteOverriddenNonVirtualTrace(CXXMethodDecl* overridden) { 1787 SourceLocation loc = overridden->getLocStart(); 1788 SourceManager& manager = instance_.getSourceManager(); 1789 FullSourceLoc full_loc(loc, manager); 1790 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_note_) 1791 << overridden; 1792 } 1793 1794 unsigned diag_class_must_left_mostly_derive_gc_; 1795 unsigned diag_class_requires_trace_method_; 1796 unsigned diag_base_requires_tracing_; 1797 unsigned diag_fields_require_tracing_; 1798 unsigned diag_class_contains_invalid_fields_; 1799 unsigned diag_class_contains_invalid_fields_warning_; 1800 unsigned diag_class_contains_gc_root_; 1801 unsigned diag_class_requires_finalization_; 1802 unsigned diag_class_does_not_require_finalization_; 1803 unsigned diag_finalizer_accesses_finalized_field_; 1804 unsigned diag_overridden_non_virtual_trace_; 1805 unsigned diag_missing_trace_dispatch_method_; 1806 unsigned diag_missing_finalize_dispatch_method_; 1807 unsigned diag_virtual_and_manual_dispatch_; 1808 unsigned diag_missing_trace_dispatch_; 1809 unsigned diag_missing_finalize_dispatch_; 1810 unsigned diag_derives_non_stack_allocated_; 1811 unsigned diag_class_overrides_new_; 1812 unsigned diag_class_declares_pure_virtual_trace_; 1813 unsigned diag_left_most_base_must_be_polymorphic_; 1814 unsigned diag_base_class_must_declare_virtual_trace_; 1815 1816 unsigned diag_base_requires_tracing_note_; 1817 unsigned diag_field_requires_tracing_note_; 1818 unsigned diag_raw_ptr_to_gc_managed_class_note_; 1819 unsigned diag_ref_ptr_to_gc_managed_class_note_; 1820 unsigned diag_own_ptr_to_gc_managed_class_note_; 1821 unsigned diag_stack_allocated_field_note_; 1822 unsigned diag_member_in_unmanaged_class_note_; 1823 unsigned diag_part_object_to_gc_derived_class_note_; 1824 unsigned diag_part_object_contains_gc_root_note_; 1825 unsigned diag_field_contains_gc_root_note_; 1826 unsigned diag_finalized_field_note_; 1827 unsigned diag_user_declared_destructor_note_; 1828 unsigned diag_user_declared_finalizer_note_; 1829 unsigned diag_base_requires_finalization_note_; 1830 unsigned diag_field_requires_finalization_note_; 1831 unsigned diag_overridden_non_virtual_trace_note_; 1832 unsigned diag_manual_dispatch_method_note_; 1833 1834 CompilerInstance& instance_; 1835 DiagnosticsEngine& diagnostic_; 1836 BlinkGCPluginOptions options_; 1837 RecordCache cache_; 1838 JsonWriter* json_; 1839 }; 1840 1841 class BlinkGCPluginAction : public PluginASTAction { 1842 public: 1843 BlinkGCPluginAction() {} 1844 1845 protected: 1846 // Overridden from PluginASTAction: 1847 virtual std::unique_ptr<ASTConsumer> CreateASTConsumer( 1848 CompilerInstance& instance, 1849 llvm::StringRef ref) { 1850 return llvm::make_unique<BlinkGCPluginConsumer>(instance, options_); 1851 } 1852 1853 virtual bool ParseArgs(const CompilerInstance& instance, 1854 const std::vector<string>& args) { 1855 bool parsed = true; 1856 1857 for (size_t i = 0; i < args.size() && parsed; ++i) { 1858 if (args[i] == "enable-oilpan") { 1859 options_.enable_oilpan = true; 1860 } else if (args[i] == "dump-graph") { 1861 options_.dump_graph = true; 1862 } else if (args[i] == "warn-raw-ptr") { 1863 options_.warn_raw_ptr = true; 1864 } else if (args[i] == "warn-unneeded-finalizer") { 1865 options_.warn_unneeded_finalizer = true; 1866 } else { 1867 parsed = false; 1868 llvm::errs() << "Unknown blink-gc-plugin argument: " << args[i] << "\n"; 1869 } 1870 } 1871 1872 return parsed; 1873 } 1874 1875 private: 1876 BlinkGCPluginOptions options_; 1877 }; 1878 1879 } // namespace 1880 1881 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 1882 "blink-gc-plugin", 1883 "Check Blink GC invariants"); 1884