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 |