OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
6 // collection infrastructure. | 6 // collection infrastructure. |
7 // | 7 // |
8 // Errors are described at: | 8 // Errors are described at: |
9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
10 | 10 |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 bool dispatched_to_receiver() { return dispatched_to_receiver_; } | 308 bool dispatched_to_receiver() { return dispatched_to_receiver_; } |
309 | 309 |
310 bool VisitMemberExpr(MemberExpr* member) { | 310 bool VisitMemberExpr(MemberExpr* member) { |
311 if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) { | 311 if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) { |
312 if (fn->getParent() == receiver_->record()) | 312 if (fn->getParent() == receiver_->record()) |
313 dispatched_to_receiver_ = true; | 313 dispatched_to_receiver_ = true; |
314 } | 314 } |
315 return true; | 315 return true; |
316 } | 316 } |
317 | 317 |
| 318 bool VisitUnresolvedMemberExpr(UnresolvedMemberExpr* member) { |
| 319 for (Decl* decl : member->decls()) { |
| 320 if (CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl)) { |
| 321 if (method->getParent() == receiver_->record() && |
| 322 Config::GetTraceMethodType(method) == |
| 323 Config::TRACE_AFTER_DISPATCH_METHOD) { |
| 324 dispatched_to_receiver_ = true; |
| 325 return true; |
| 326 } |
| 327 } |
| 328 } |
| 329 return true; |
| 330 } |
| 331 |
318 private: | 332 private: |
319 RecordInfo* receiver_; | 333 RecordInfo* receiver_; |
320 bool dispatched_to_receiver_; | 334 bool dispatched_to_receiver_; |
321 }; | 335 }; |
322 | 336 |
323 // This visitor checks a tracing method by traversing its body. | 337 // This visitor checks a tracing method by traversing its body. |
324 // - A member field is considered traced if it is referenced in the body. | 338 // - A member field is considered traced if it is referenced in the body. |
325 // - A base is traced if a base-qualified call to a trace method is found. | 339 // - A base is traced if a base-qualified call to a trace method is found. |
326 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { | 340 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
327 public: | 341 public: |
328 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) | 342 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info, RecordCache* cache) |
329 : trace_(trace), info_(info), delegates_to_traceimpl_(false) {} | 343 : trace_(trace), |
| 344 info_(info), |
| 345 cache_(cache), |
| 346 delegates_to_traceimpl_(false) { |
| 347 } |
330 | 348 |
331 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; } | 349 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; } |
332 | 350 |
333 bool VisitMemberExpr(MemberExpr* member) { | 351 bool VisitMemberExpr(MemberExpr* member) { |
334 // In weak callbacks, consider any occurrence as a correct usage. | 352 // In weak callbacks, consider any occurrence as a correct usage. |
335 // TODO: We really want to require that isAlive is checked on manually | 353 // TODO: We really want to require that isAlive is checked on manually |
336 // processed weak fields. | 354 // processed weak fields. |
337 if (IsWeakCallback()) { | 355 if (IsWeakCallback()) { |
338 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) | 356 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) |
339 FoundField(field); | 357 FoundField(field); |
(...skipping 23 matching lines...) Expand all Loading... |
363 if (call->getNumArgs() != 1) | 381 if (call->getNumArgs() != 1) |
364 return true; | 382 return true; |
365 Expr* arg = call->getArg(0); | 383 Expr* arg = call->getArg(0); |
366 | 384 |
367 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { | 385 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { |
368 // This could be a trace call of a base class, as explained in the | 386 // This could be a trace call of a base class, as explained in the |
369 // comments of CheckTraceBaseCall(). | 387 // comments of CheckTraceBaseCall(). |
370 if (CheckTraceBaseCall(call)) | 388 if (CheckTraceBaseCall(call)) |
371 return true; | 389 return true; |
372 | 390 |
373 // If we find a call to registerWeakMembers which is unresolved we | 391 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) |
374 // unsoundly consider all weak members as traced. | 392 MarkAllWeakMembersTraced(); |
375 // TODO: Find out how to validate weak member tracing for unresolved call. | |
376 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { | |
377 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); | |
378 it != info_->GetFields().end(); | |
379 ++it) { | |
380 if (it->second.edge()->IsWeakMember()) | |
381 it->second.MarkTraced(); | |
382 } | |
383 } | |
384 | 393 |
385 QualType base = expr->getBaseType(); | 394 QualType base = expr->getBaseType(); |
386 if (!base->isPointerType()) | 395 if (!base->isPointerType()) |
387 return true; | 396 return true; |
388 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); | 397 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); |
389 if (decl) | 398 if (decl) |
390 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); | 399 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); |
391 if (Config::IsTraceImplName(expr->getMemberName().getAsString())) | 400 if (Config::IsTraceImplName(expr->getMemberName().getAsString())) |
392 delegates_to_traceimpl_ = true; | 401 delegates_to_traceimpl_ = true; |
393 return true; | 402 return true; |
394 } | 403 } |
395 | 404 |
396 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { | 405 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { |
397 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) | 406 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) |
398 return true; | 407 return true; |
399 | 408 |
400 if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) { | 409 if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) { |
401 delegates_to_traceimpl_ = true; | 410 delegates_to_traceimpl_ = true; |
402 return true; | 411 return true; |
403 } | 412 } |
404 } | 413 } |
405 | 414 |
406 CheckTraceBaseCall(call); | 415 CheckTraceBaseCall(call); |
407 return true; | 416 return true; |
408 } | 417 } |
409 | 418 |
410 private: | 419 private: |
| 420 bool IsTraceCallName(const std::string& name) { |
| 421 if (trace_->getName() == kTraceImplName) |
| 422 return name == kTraceName; |
| 423 if (trace_->getName() == kTraceAfterDispatchImplName) |
| 424 return name == kTraceAfterDispatchName; |
| 425 // Currently, a manually dispatched class cannot have mixin bases (having |
| 426 // one would add a vtable which we explicitly check against). This means |
| 427 // that we can only make calls to a trace method of the same name. Revisit |
| 428 // this if our mixin/vtable assumption changes. |
| 429 return name == trace_->getName(); |
| 430 } |
| 431 |
411 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { | 432 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { |
412 NestedNameSpecifier* qual = expr->getQualifier(); | 433 NestedNameSpecifier* qual = expr->getQualifier(); |
413 if (!qual) | 434 if (!qual) |
414 return 0; | 435 return 0; |
415 | 436 |
416 const Type* type = qual->getAsType(); | 437 const Type* type = qual->getAsType(); |
417 if (!type) | 438 if (!type) |
418 return 0; | 439 return 0; |
419 | 440 |
420 return RecordInfo::GetDependentTemplatedDecl(*type); | 441 return RecordInfo::GetDependentTemplatedDecl(*type); |
421 } | 442 } |
422 | 443 |
423 void CheckCXXDependentScopeMemberExpr(CallExpr* call, | 444 void CheckCXXDependentScopeMemberExpr(CallExpr* call, |
424 CXXDependentScopeMemberExpr* expr) { | 445 CXXDependentScopeMemberExpr* expr) { |
425 string fn_name = expr->getMember().getAsString(); | 446 string fn_name = expr->getMember().getAsString(); |
426 | 447 |
427 // Check for VisitorDispatcher::trace(field) | 448 // Check for VisitorDispatcher::trace(field) and |
| 449 // VisitorDispatcher::registerWeakMembers. |
428 if (!expr->isImplicitAccess()) { | 450 if (!expr->isImplicitAccess()) { |
429 if (clang::DeclRefExpr* base_decl = | 451 if (clang::DeclRefExpr* base_decl = |
430 clang::dyn_cast<clang::DeclRefExpr>(expr->getBase())) { | 452 clang::dyn_cast<clang::DeclRefExpr>(expr->getBase())) { |
431 if (Config::IsVisitorDispatcherType(base_decl->getType()) && | 453 if (Config::IsVisitorDispatcherType(base_decl->getType())) { |
432 call->getNumArgs() == 1 && fn_name == kTraceName) { | 454 if (call->getNumArgs() == 1 && fn_name == kTraceName) { |
433 FindFieldVisitor finder; | 455 FindFieldVisitor finder; |
434 finder.TraverseStmt(call->getArg(0)); | 456 finder.TraverseStmt(call->getArg(0)); |
435 if (finder.field()) | 457 if (finder.field()) |
436 FoundField(finder.field()); | 458 FoundField(finder.field()); |
437 | 459 |
438 return; | 460 return; |
| 461 } else if (call->getNumArgs() == 1 && |
| 462 fn_name == kRegisterWeakMembersName) { |
| 463 MarkAllWeakMembersTraced(); |
| 464 } |
439 } | 465 } |
440 } | 466 } |
441 } | 467 } |
442 | 468 |
443 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); | 469 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); |
444 if (!tmpl) | 470 if (!tmpl) |
445 return; | 471 return; |
446 | 472 |
447 // Check for Super<T>::trace(visitor) | 473 // Check for Super<T>::trace(visitor) |
448 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) { | 474 if (call->getNumArgs() == 1 && IsTraceCallName(fn_name)) { |
449 RecordInfo::Bases::iterator it = info_->GetBases().begin(); | 475 RecordInfo::Bases::iterator it = info_->GetBases().begin(); |
450 for (; it != info_->GetBases().end(); ++it) { | 476 for (; it != info_->GetBases().end(); ++it) { |
451 if (it->first->getName() == tmpl->getName()) | 477 if (it->first->getName() == tmpl->getName()) |
452 it->second.MarkTraced(); | 478 it->second.MarkTraced(); |
453 } | 479 } |
454 return; | |
455 } | 480 } |
456 | 481 |
457 // Check for TraceIfNeeded<T>::trace(visitor, &field) | 482 // Check for TraceIfNeeded<T>::trace(visitor, &field) |
458 if (call->getNumArgs() == 2 && fn_name == kTraceName && | 483 if (call->getNumArgs() == 2 && fn_name == kTraceName && |
459 tmpl->getName() == kTraceIfNeededName) { | 484 tmpl->getName() == kTraceIfNeededName) { |
460 FindFieldVisitor finder; | 485 FindFieldVisitor finder; |
461 finder.TraverseStmt(call->getArg(1)); | 486 finder.TraverseStmt(call->getArg(1)); |
462 if (finder.field()) | 487 if (finder.field()) |
463 FoundField(finder.field()); | 488 FoundField(finder.field()); |
464 } | 489 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 if (call->getNumArgs() != 1) | 542 if (call->getNumArgs() != 1) |
518 return false; | 543 return false; |
519 DeclRefExpr* arg = dyn_cast<DeclRefExpr>(call->getArg(0)); | 544 DeclRefExpr* arg = dyn_cast<DeclRefExpr>(call->getArg(0)); |
520 if (!arg || arg->getNameInfo().getAsString() != kVisitorVarName) | 545 if (!arg || arg->getNameInfo().getAsString() != kVisitorVarName) |
521 return false; | 546 return false; |
522 | 547 |
523 callee_record = trace_decl->getParent(); | 548 callee_record = trace_decl->getParent(); |
524 func_name = callee->getMemberName().getAsString(); | 549 func_name = callee->getMemberName().getAsString(); |
525 } | 550 } |
526 | 551 |
527 if (trace_->getName() == kTraceImplName) { | |
528 if (func_name != kTraceName) | |
529 return false; | |
530 } else if (trace_->getName() == kTraceAfterDispatchImplName) { | |
531 if (func_name != kTraceAfterDispatchName) | |
532 return false; | |
533 } else { | |
534 // Currently, a manually dispatched class cannot have mixin bases (having | |
535 // one would add a vtable which we explicitly check against). This means | |
536 // that we can only make calls to a trace method of the same name. Revisit | |
537 // this if our mixin/vtable assumption changes. | |
538 if (func_name != trace_->getName()) | |
539 return false; | |
540 } | |
541 | |
542 if (!callee_record) | 552 if (!callee_record) |
543 return false; | 553 return false; |
544 RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record); | 554 |
545 if (iter == info_->GetBases().end()) | 555 if (!IsTraceCallName(func_name)) |
546 return false; | 556 return false; |
547 | 557 |
548 iter->second.MarkTraced(); | 558 for (auto& base : info_->GetBases()) { |
549 return true; | 559 // We want to deal with omitted trace() function in an intermediary |
| 560 // class in the class hierarchy, e.g.: |
| 561 // class A : public GarbageCollected<A> { trace() { ... } }; |
| 562 // class B : public A { /* No trace(); have nothing to trace. */ }; |
| 563 // class C : public B { trace() { B::trace(visitor); } } |
| 564 // where, B::trace() is actually A::trace(), and in some cases we get |
| 565 // A as |callee_record| instead of B. We somehow need to mark B as |
| 566 // traced if we find A::trace() call. |
| 567 // |
| 568 // To solve this, here we keep going up the class hierarchy as long as |
| 569 // they are not required to have a trace method. The implementation is |
| 570 // a simple DFS, where |base_records| represents the set of base classes |
| 571 // we need to visit. |
| 572 |
| 573 std::vector<CXXRecordDecl*> base_records; |
| 574 base_records.push_back(base.first); |
| 575 |
| 576 while (!base_records.empty()) { |
| 577 CXXRecordDecl* base_record = base_records.back(); |
| 578 base_records.pop_back(); |
| 579 |
| 580 if (base_record == callee_record) { |
| 581 // If we find a matching trace method, pretend the user has written |
| 582 // a correct trace() method of the base; in the example above, we |
| 583 // find A::trace() here and mark B as correctly traced. |
| 584 base.second.MarkTraced(); |
| 585 return true; |
| 586 } |
| 587 |
| 588 if (RecordInfo* base_info = cache_->Lookup(base_record)) { |
| 589 if (!base_info->RequiresTraceMethod()) { |
| 590 // If this base class is not required to have a trace method, then |
| 591 // the actual trace method may be defined in an ancestor. |
| 592 for (auto& inner_base : base_info->GetBases()) |
| 593 base_records.push_back(inner_base.first); |
| 594 } |
| 595 } |
| 596 } |
| 597 } |
| 598 |
| 599 return false; |
550 } | 600 } |
551 | 601 |
552 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { | 602 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { |
553 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), | 603 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), |
554 call->getRecordDecl(), | 604 call->getRecordDecl(), |
555 call->getArg(0)); | 605 call->getArg(0)); |
556 } | 606 } |
557 | 607 |
558 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { | 608 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { |
559 if (name != kTraceName || !Config::IsVisitor(callee->getName())) | 609 if (name != kTraceName || !Config::IsVisitor(callee->getName())) |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 return false; | 652 return false; |
603 } | 653 } |
604 return true; | 654 return true; |
605 } | 655 } |
606 private: | 656 private: |
607 MemberExpr* member_; | 657 MemberExpr* member_; |
608 FieldDecl* field_; | 658 FieldDecl* field_; |
609 }; | 659 }; |
610 | 660 |
611 // Nested checking for weak callbacks. | 661 // Nested checking for weak callbacks. |
612 CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} | 662 CheckTraceVisitor(RecordInfo* info) |
| 663 : trace_(nullptr), info_(info), cache_(nullptr) {} |
613 | 664 |
614 bool IsWeakCallback() { return !trace_; } | 665 bool IsWeakCallback() { return !trace_; } |
615 | 666 |
616 void MarkTraced(RecordInfo::Fields::iterator it) { | 667 void MarkTraced(RecordInfo::Fields::iterator it) { |
617 // In a weak callback we can't mark strong fields as traced. | 668 // In a weak callback we can't mark strong fields as traced. |
618 if (IsWeakCallback() && !it->second.edge()->IsWeakMember()) | 669 if (IsWeakCallback() && !it->second.edge()->IsWeakMember()) |
619 return; | 670 return; |
620 it->second.MarkTraced(); | 671 it->second.MarkTraced(); |
621 } | 672 } |
622 | 673 |
(...skipping 11 matching lines...) Expand all Loading... |
634 break; | 685 break; |
635 } | 686 } |
636 } | 687 } |
637 } else { | 688 } else { |
638 RecordInfo::Fields::iterator it = info_->GetFields().find(field); | 689 RecordInfo::Fields::iterator it = info_->GetFields().find(field); |
639 if (it != info_->GetFields().end()) | 690 if (it != info_->GetFields().end()) |
640 MarkTraced(it); | 691 MarkTraced(it); |
641 } | 692 } |
642 } | 693 } |
643 | 694 |
| 695 void MarkAllWeakMembersTraced() { |
| 696 // If we find a call to registerWeakMembers which is unresolved we |
| 697 // unsoundly consider all weak members as traced. |
| 698 // TODO: Find out how to validate weak member tracing for unresolved call. |
| 699 for (auto& field : info_->GetFields()) { |
| 700 if (field.second.edge()->IsWeakMember()) |
| 701 field.second.MarkTraced(); |
| 702 } |
| 703 } |
| 704 |
644 CXXMethodDecl* trace_; | 705 CXXMethodDecl* trace_; |
645 RecordInfo* info_; | 706 RecordInfo* info_; |
| 707 RecordCache* cache_; |
646 bool delegates_to_traceimpl_; | 708 bool delegates_to_traceimpl_; |
647 }; | 709 }; |
648 | 710 |
649 // This visitor checks that the fields of a class and the fields of | 711 // This visitor checks that the fields of a class and the fields of |
650 // its part objects don't define GC roots. | 712 // its part objects don't define GC roots. |
651 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { | 713 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { |
652 public: | 714 public: |
653 typedef std::vector<FieldPoint*> RootPath; | 715 typedef std::vector<FieldPoint*> RootPath; |
654 typedef std::set<RecordInfo*> VisitingSet; | 716 typedef std::set<RecordInfo*> VisitingSet; |
655 typedef std::vector<RootPath> Errors; | 717 typedef std::vector<RootPath> Errors; |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1062 if (visitor.ContainsInvalidFields(info)) | 1124 if (visitor.ContainsInvalidFields(info)) |
1063 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); | 1125 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); |
1064 } | 1126 } |
1065 | 1127 |
1066 if (info->IsGCDerived()) { | 1128 if (info->IsGCDerived()) { |
1067 | 1129 |
1068 if (!info->IsGCMixin()) { | 1130 if (!info->IsGCMixin()) { |
1069 CheckLeftMostDerived(info); | 1131 CheckLeftMostDerived(info); |
1070 CheckDispatch(info); | 1132 CheckDispatch(info); |
1071 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) | 1133 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) |
1072 ReportClassOverridesNew(info, newop); | 1134 if (!Config::IsIgnoreAnnotated(newop)) |
| 1135 ReportClassOverridesNew(info, newop); |
1073 if (info->IsGCMixinInstance()) { | 1136 if (info->IsGCMixinInstance()) { |
1074 // Require that declared GCMixin implementations | 1137 // Require that declared GCMixin implementations |
1075 // also provide a trace() override. | 1138 // also provide a trace() override. |
1076 if (info->DeclaresGCMixinMethods() | 1139 if (info->DeclaresGCMixinMethods() |
1077 && !info->DeclaresLocalTraceMethod()) | 1140 && !info->DeclaresLocalTraceMethod()) |
1078 ReportClassMustDeclareGCMixinTraceMethod(info); | 1141 ReportClassMustDeclareGCMixinTraceMethod(info); |
1079 } | 1142 } |
1080 } | 1143 } |
1081 | 1144 |
1082 { | 1145 { |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1358 } | 1421 } |
1359 return; | 1422 return; |
1360 } | 1423 } |
1361 | 1424 |
1362 CheckTraceOrDispatchMethod(parent, method); | 1425 CheckTraceOrDispatchMethod(parent, method); |
1363 } | 1426 } |
1364 | 1427 |
1365 // Determine what type of tracing method this is (dispatch or trace). | 1428 // Determine what type of tracing method this is (dispatch or trace). |
1366 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { | 1429 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { |
1367 Config::TraceMethodType trace_type = Config::GetTraceMethodType(method); | 1430 Config::TraceMethodType trace_type = Config::GetTraceMethodType(method); |
1368 if (trace_type != Config::TRACE_METHOD || | 1431 if (trace_type == Config::TRACE_AFTER_DISPATCH_METHOD || |
| 1432 trace_type == Config::TRACE_AFTER_DISPATCH_IMPL_METHOD || |
1369 !parent->GetTraceDispatchMethod()) { | 1433 !parent->GetTraceDispatchMethod()) { |
1370 CheckTraceMethod(parent, method, trace_type); | 1434 CheckTraceMethod(parent, method, trace_type); |
1371 } | 1435 } |
1372 // Dispatch methods are checked when we identify subclasses. | 1436 // Dispatch methods are checked when we identify subclasses. |
1373 } | 1437 } |
1374 | 1438 |
1375 // Check an actual trace method. | 1439 // Check an actual trace method. |
1376 void CheckTraceMethod(RecordInfo* parent, | 1440 void CheckTraceMethod(RecordInfo* parent, |
1377 CXXMethodDecl* trace, | 1441 CXXMethodDecl* trace, |
1378 Config::TraceMethodType trace_type) { | 1442 Config::TraceMethodType trace_type) { |
1379 // A trace method must not override any non-virtual trace methods. | 1443 // A trace method must not override any non-virtual trace methods. |
1380 if (trace_type == Config::TRACE_METHOD) { | 1444 if (trace_type == Config::TRACE_METHOD) { |
1381 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 1445 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
1382 it != parent->GetBases().end(); | 1446 it != parent->GetBases().end(); |
1383 ++it) { | 1447 ++it) { |
1384 RecordInfo* base = it->second.info(); | 1448 RecordInfo* base = it->second.info(); |
1385 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) | 1449 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) |
1386 ReportOverriddenNonVirtualTrace(parent, trace, other); | 1450 ReportOverriddenNonVirtualTrace(parent, trace, other); |
1387 } | 1451 } |
1388 } | 1452 } |
1389 | 1453 |
1390 CheckTraceVisitor visitor(trace, parent); | 1454 CheckTraceVisitor visitor(trace, parent, &cache_); |
1391 visitor.TraverseCXXMethodDecl(trace); | 1455 visitor.TraverseCXXMethodDecl(trace); |
1392 | 1456 |
1393 // Skip reporting if this trace method is a just delegate to | 1457 // Skip reporting if this trace method is a just delegate to |
1394 // traceImpl (or traceAfterDispatchImpl) method. We will report on | 1458 // traceImpl (or traceAfterDispatchImpl) method. We will report on |
1395 // CheckTraceMethod on traceImpl method. | 1459 // CheckTraceMethod on traceImpl method. |
1396 if (visitor.delegates_to_traceimpl()) | 1460 if (visitor.delegates_to_traceimpl()) |
1397 return; | 1461 return; |
1398 | 1462 |
1399 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 1463 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
1400 it != parent->GetBases().end(); | 1464 it != parent->GetBases().end(); |
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1990 | 2054 |
1991 private: | 2055 private: |
1992 BlinkGCPluginOptions options_; | 2056 BlinkGCPluginOptions options_; |
1993 }; | 2057 }; |
1994 | 2058 |
1995 } // namespace | 2059 } // namespace |
1996 | 2060 |
1997 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 2061 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
1998 "blink-gc-plugin", | 2062 "blink-gc-plugin", |
1999 "Check Blink GC invariants"); | 2063 "Check Blink GC invariants"); |
OLD | NEW |