Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This clang plugin checks various invariants of the Blink garbage | 5 // This clang plugin checks various invariants of the Blink garbage |
| 6 // collection infrastructure. | 6 // collection infrastructure. |
| 7 // | 7 // |
| 8 // Errors are described at: | 8 // Errors are described at: |
| 9 // http://www.chromium.org/developers/blink-gc-plugin-errors | 9 // http://www.chromium.org/developers/blink-gc-plugin-errors |
| 10 | 10 |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 return true; | 358 return true; |
| 359 } | 359 } |
| 360 | 360 |
| 361 // A tracing call will have either a |visitor| or a |m_field| argument. | 361 // A tracing call will have either a |visitor| or a |m_field| argument. |
| 362 // A registerWeakMembers call will have a |this| argument. | 362 // A registerWeakMembers call will have a |this| argument. |
| 363 if (call->getNumArgs() != 1) | 363 if (call->getNumArgs() != 1) |
| 364 return true; | 364 return true; |
| 365 Expr* arg = call->getArg(0); | 365 Expr* arg = call->getArg(0); |
| 366 | 366 |
| 367 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { | 367 if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { |
| 368 // This could be a trace call of a base class, as explained in the | |
| 369 // comments of CheckTraceBaseCall(). | |
| 370 if (CheckTraceBaseCall(call)) | |
| 371 return true; | |
| 372 | |
| 368 // If we find a call to registerWeakMembers which is unresolved we | 373 // If we find a call to registerWeakMembers which is unresolved we |
| 369 // unsoundly consider all weak members as traced. | 374 // unsoundly consider all weak members as traced. |
| 370 // TODO: Find out how to validate weak member tracing for unresolved call. | 375 // TODO: Find out how to validate weak member tracing for unresolved call. |
| 371 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { | 376 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { |
| 372 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); | 377 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); |
| 373 it != info_->GetFields().end(); | 378 it != info_->GetFields().end(); |
| 374 ++it) { | 379 ++it) { |
| 375 if (it->second.edge()->IsWeakMember()) | 380 if (it->second.edge()->IsWeakMember()) |
| 376 it->second.MarkTraced(); | 381 it->second.MarkTraced(); |
| 377 } | 382 } |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 396 delegates_to_traceimpl_ = true; | 401 delegates_to_traceimpl_ = true; |
| 397 return true; | 402 return true; |
| 398 } | 403 } |
| 399 } | 404 } |
| 400 | 405 |
| 401 CheckTraceBaseCall(call); | 406 CheckTraceBaseCall(call); |
| 402 return true; | 407 return true; |
| 403 } | 408 } |
| 404 | 409 |
| 405 private: | 410 private: |
| 406 | |
| 407 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { | 411 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { |
| 408 NestedNameSpecifier* qual = expr->getQualifier(); | 412 NestedNameSpecifier* qual = expr->getQualifier(); |
| 409 if (!qual) | 413 if (!qual) |
| 410 return 0; | 414 return 0; |
| 411 | 415 |
| 412 const Type* type = qual->getAsType(); | 416 const Type* type = qual->getAsType(); |
| 413 if (!type) | 417 if (!type) |
| 414 return 0; | 418 return 0; |
| 415 | 419 |
| 416 return RecordInfo::GetDependentTemplatedDecl(*type); | 420 return RecordInfo::GetDependentTemplatedDecl(*type); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 454 if (call->getNumArgs() == 2 && fn_name == kTraceName && | 458 if (call->getNumArgs() == 2 && fn_name == kTraceName && |
| 455 tmpl->getName() == kTraceIfNeededName) { | 459 tmpl->getName() == kTraceIfNeededName) { |
| 456 FindFieldVisitor finder; | 460 FindFieldVisitor finder; |
| 457 finder.TraverseStmt(call->getArg(1)); | 461 finder.TraverseStmt(call->getArg(1)); |
| 458 if (finder.field()) | 462 if (finder.field()) |
| 459 FoundField(finder.field()); | 463 FoundField(finder.field()); |
| 460 } | 464 } |
| 461 } | 465 } |
| 462 | 466 |
| 463 bool CheckTraceBaseCall(CallExpr* call) { | 467 bool CheckTraceBaseCall(CallExpr* call) { |
| 464 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); | 468 // Checks for "Base::trace(visitor)"-like calls. |
| 465 if (!callee) | |
| 466 return false; | |
| 467 | 469 |
| 468 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); | 470 // Checking code for these two variables is shared among MemberExpr* case |
| 469 if (!fn || !Config::IsTraceMethod(fn)) | 471 // and UnresolvedMemberCase* case below. |
| 470 return false; | 472 // |
| 473 // For example, if we've got "Base::trace(visitor)" as |call|, | |
| 474 // callee_record will be "Base", and func_name will be "trace". | |
| 475 CXXRecordDecl* callee_record = nullptr; | |
| 476 std::string func_name; | |
| 477 | |
| 478 if (MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee())) { | |
| 479 if (!callee->hasQualifier()) | |
| 480 return false; | |
| 481 | |
| 482 FunctionDecl* trace_decl = | |
| 483 dyn_cast<FunctionDecl>(callee->getMemberDecl()); | |
| 484 if (!trace_decl || !Config::IsTraceMethod(trace_decl)) | |
| 485 return false; | |
| 486 | |
| 487 const Type* type = callee->getQualifier()->getAsType(); | |
| 488 if (!type) | |
| 489 return false; | |
| 490 | |
| 491 callee_record = type->getAsCXXRecordDecl(); | |
| 492 func_name = trace_decl->getName(); | |
| 493 } else if (UnresolvedMemberExpr* callee = | |
| 494 dyn_cast<UnresolvedMemberExpr>(call->getCallee())) { | |
| 495 // Callee part may become unresolved if the type of the argument | |
| 496 // ("visitor") is a template parameter and the called function is | |
| 497 // overloaded (i.e. trace(Visitor*) and | |
| 498 // trace(InlinedGlobalMarkingVisitor)). | |
| 499 // | |
| 500 // Here, we try to find a function that looks like trace() from the | |
| 501 // candidate overloaded functions, and if we find one, we assume it is | |
| 502 // called here. | |
| 503 | |
| 504 CXXMethodDecl* trace_decl = nullptr; | |
| 505 for (NamedDecl* named_decl : callee->decls()) { | |
| 506 if (CXXMethodDecl* method_decl = dyn_cast<CXXMethodDecl>(named_decl)) { | |
| 507 if (Config::IsTraceMethod(method_decl)) { | |
| 508 trace_decl = method_decl; | |
| 509 break; | |
| 510 } | |
| 511 } | |
| 512 } | |
| 513 if (!trace_decl) | |
| 514 return false; | |
| 515 | |
| 516 // Check if the passed argument is named "visitor". | |
|
kouhei (in TOK)
2015/02/24 07:46:32
Nit: Should we document this change in CL desc?
Yuta Kitamura
2015/02/24 08:35:58
Done.
| |
| 517 if (call->getNumArgs() != 1) | |
| 518 return false; | |
| 519 DeclRefExpr* arg = dyn_cast<DeclRefExpr>(call->getArg(0)); | |
| 520 if (!arg || arg->getNameInfo().getAsString() != kVisitorVarName) | |
| 521 return false; | |
| 522 | |
| 523 callee_record = trace_decl->getParent(); | |
| 524 func_name = callee->getMemberName().getAsString(); | |
| 525 } | |
| 471 | 526 |
| 472 if (trace_->getName() == kTraceImplName) { | 527 if (trace_->getName() == kTraceImplName) { |
| 473 if (fn->getName() != kTraceName) | 528 if (func_name != kTraceName) |
| 474 return false; | 529 return false; |
| 475 } else if (trace_->getName() == kTraceAfterDispatchImplName) { | 530 } else if (trace_->getName() == kTraceAfterDispatchImplName) { |
| 476 if (fn->getName() != kTraceAfterDispatchName) | 531 if (func_name != kTraceAfterDispatchName) |
| 477 return false; | 532 return false; |
| 478 } else { | 533 } else { |
| 479 // Currently, a manually dispatched class cannot have mixin bases (having | 534 // Currently, a manually dispatched class cannot have mixin bases (having |
| 480 // one would add a vtable which we explicitly check against). This means | 535 // one would add a vtable which we explicitly check against). This means |
| 481 // that we can only make calls to a trace method of the same name. Revisit | 536 // that we can only make calls to a trace method of the same name. Revisit |
| 482 // this if our mixin/vtable assumption changes. | 537 // this if our mixin/vtable assumption changes. |
| 483 if (fn->getName() != trace_->getName()) | 538 if (func_name != trace_->getName()) |
| 484 return false; | 539 return false; |
| 485 } | 540 } |
| 486 | 541 |
| 487 CXXRecordDecl* decl = 0; | 542 if (!callee_record) |
| 488 if (callee && callee->hasQualifier()) { | 543 return false; |
| 489 if (const Type* type = callee->getQualifier()->getAsType()) | 544 RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record); |
| 490 decl = type->getAsCXXRecordDecl(); | 545 if (iter == info_->GetBases().end()) |
| 491 } | |
| 492 if (!decl) | |
| 493 return false; | 546 return false; |
| 494 | 547 |
| 495 RecordInfo::Bases::iterator it = info_->GetBases().find(decl); | 548 iter->second.MarkTraced(); |
| 496 if (it != info_->GetBases().end()) { | |
| 497 it->second.MarkTraced(); | |
| 498 } | |
| 499 | |
| 500 return true; | 549 return true; |
| 501 } | 550 } |
| 502 | 551 |
| 503 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { | 552 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { |
| 504 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), | 553 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), |
| 505 call->getRecordDecl(), | 554 call->getRecordDecl(), |
| 506 call->getArg(0)); | 555 call->getArg(0)); |
| 507 } | 556 } |
| 508 | 557 |
| 509 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { | 558 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { |
| (...skipping 1431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1941 | 1990 |
| 1942 private: | 1991 private: |
| 1943 BlinkGCPluginOptions options_; | 1992 BlinkGCPluginOptions options_; |
| 1944 }; | 1993 }; |
| 1945 | 1994 |
| 1946 } // namespace | 1995 } // namespace |
| 1947 | 1996 |
| 1948 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1997 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
| 1949 "blink-gc-plugin", | 1998 "blink-gc-plugin", |
| 1950 "Check Blink GC invariants"); | 1999 "Check Blink GC invariants"); |
| OLD | NEW |