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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 RecordInfo* receiver_; | 315 RecordInfo* receiver_; |
| 316 bool dispatched_to_receiver_; | 316 bool dispatched_to_receiver_; |
| 317 }; | 317 }; |
| 318 | 318 |
| 319 // This visitor checks a tracing method by traversing its body. | 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. | 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. | 321 // - A base is traced if a base-qualified call to a trace method is found. |
| 322 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { | 322 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
| 323 public: | 323 public: |
| 324 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) | 324 CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) |
| 325 : trace_(trace), info_(info) {} | 325 : trace_(trace), info_(info), delegates_to_traceimpl_(false) {} |
| 326 | |
| 327 bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; } | |
| 326 | 328 |
| 327 bool VisitMemberExpr(MemberExpr* member) { | 329 bool VisitMemberExpr(MemberExpr* member) { |
| 328 // In weak callbacks, consider any occurrence as a correct usage. | 330 // In weak callbacks, consider any occurrence as a correct usage. |
| 329 // TODO: We really want to require that isAlive is checked on manually | 331 // TODO: We really want to require that isAlive is checked on manually |
| 330 // processed weak fields. | 332 // processed weak fields. |
| 331 if (IsWeakCallback()) { | 333 if (IsWeakCallback()) { |
| 332 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) | 334 if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) |
| 333 FoundField(field); | 335 FoundField(field); |
| 334 } | 336 } |
| 335 return true; | 337 return true; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 return true; | 378 return true; |
| 377 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); | 379 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); |
| 378 if (decl) | 380 if (decl) |
| 379 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); | 381 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); |
| 380 return true; | 382 return true; |
| 381 } | 383 } |
| 382 | 384 |
| 383 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { | 385 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { |
| 384 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) | 386 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) |
| 385 return true; | 387 return true; |
| 388 | |
| 389 if (expr->getMethodDecl()->getNameAsString() == kTraceImplName) { | |
| 390 delegates_to_traceimpl_ = true; | |
| 391 return true; | |
| 392 } | |
| 386 } | 393 } |
| 387 | 394 |
| 388 CheckTraceBaseCall(call); | 395 CheckTraceBaseCall(call); |
| 389 return true; | 396 return true; |
| 390 } | 397 } |
| 391 | 398 |
| 392 private: | 399 private: |
| 393 | 400 |
| 394 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { | 401 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { |
| 395 NestedNameSpecifier* qual = expr->getQualifier(); | 402 NestedNameSpecifier* qual = expr->getQualifier(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 408 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); | 415 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); |
| 409 if (!tmpl_decl) | 416 if (!tmpl_decl) |
| 410 return 0; | 417 return 0; |
| 411 | 418 |
| 412 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); | 419 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); |
| 413 } | 420 } |
| 414 | 421 |
| 415 void CheckCXXDependentScopeMemberExpr(CallExpr* call, | 422 void CheckCXXDependentScopeMemberExpr(CallExpr* call, |
| 416 CXXDependentScopeMemberExpr* expr) { | 423 CXXDependentScopeMemberExpr* expr) { |
| 417 string fn_name = expr->getMember().getAsString(); | 424 string fn_name = expr->getMember().getAsString(); |
| 425 | |
| 426 // Check for VisitorDispatcher::trace(field) | |
| 427 if (!expr->isImplicitAccess()) { | |
| 428 if (clang::DeclRefExpr* base_decl = | |
| 429 clang::dyn_cast<clang::DeclRefExpr>(expr->getBase())) { | |
| 430 if (Config::IsVisitorDispatcherType(base_decl->getType()) && | |
| 431 call->getNumArgs() == 1 && fn_name == kTraceName) { | |
| 432 FindFieldVisitor finder; | |
| 433 finder.TraverseStmt(call->getArg(0)); | |
| 434 if (finder.field()) | |
| 435 FoundField(finder.field()); | |
| 436 | |
| 437 return; | |
| 438 } | |
| 439 } | |
| 440 } | |
| 441 | |
| 418 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); | 442 CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr); |
| 419 if (!tmpl) | 443 if (!tmpl) |
| 420 return; | 444 return; |
| 421 | 445 |
| 422 // Check for Super<T>::trace(visitor) | 446 // Check for Super<T>::trace(visitor) |
| 423 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) { | 447 if (call->getNumArgs() == 1 && fn_name == trace_->getName()) { |
| 424 RecordInfo::Bases::iterator it = info_->GetBases().begin(); | 448 RecordInfo::Bases::iterator it = info_->GetBases().begin(); |
| 425 for (; it != info_->GetBases().end(); ++it) { | 449 for (; it != info_->GetBases().end(); ++it) { |
| 426 if (it->first->getName() == tmpl->getName()) | 450 if (it->first->getName() == tmpl->getName()) |
| 427 it->second.MarkTraced(); | 451 it->second.MarkTraced(); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 558 } | 582 } |
| 559 } else { | 583 } else { |
| 560 RecordInfo::Fields::iterator it = info_->GetFields().find(field); | 584 RecordInfo::Fields::iterator it = info_->GetFields().find(field); |
| 561 if (it != info_->GetFields().end()) | 585 if (it != info_->GetFields().end()) |
| 562 MarkTraced(it); | 586 MarkTraced(it); |
| 563 } | 587 } |
| 564 } | 588 } |
| 565 | 589 |
| 566 CXXMethodDecl* trace_; | 590 CXXMethodDecl* trace_; |
| 567 RecordInfo* info_; | 591 RecordInfo* info_; |
| 592 bool delegates_to_traceimpl_; | |
| 568 }; | 593 }; |
| 569 | 594 |
| 570 // This visitor checks that the fields of a class and the fields of | 595 // This visitor checks that the fields of a class and the fields of |
| 571 // its part objects don't define GC roots. | 596 // its part objects don't define GC roots. |
| 572 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { | 597 class CheckGCRootsVisitor : public RecursiveEdgeVisitor { |
| 573 public: | 598 public: |
| 574 typedef std::vector<FieldPoint*> RootPath; | 599 typedef std::vector<FieldPoint*> RootPath; |
| 575 typedef std::set<RecordInfo*> VisitingSet; | 600 typedef std::set<RecordInfo*> VisitingSet; |
| 576 typedef std::vector<RootPath> Errors; | 601 typedef std::vector<RootPath> Errors; |
| 577 | 602 |
| (...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1296 ++it) { | 1321 ++it) { |
| 1297 RecordInfo* base = it->second.info(); | 1322 RecordInfo* base = it->second.info(); |
| 1298 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) | 1323 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) |
| 1299 ReportOverriddenNonVirtualTrace(parent, trace, other); | 1324 ReportOverriddenNonVirtualTrace(parent, trace, other); |
| 1300 } | 1325 } |
| 1301 } | 1326 } |
| 1302 | 1327 |
| 1303 CheckTraceVisitor visitor(trace, parent); | 1328 CheckTraceVisitor visitor(trace, parent); |
| 1304 visitor.TraverseCXXMethodDecl(trace); | 1329 visitor.TraverseCXXMethodDecl(trace); |
| 1305 | 1330 |
| 1331 // Skip reporting if this trace method is a just delegate to | |
| 1332 // traceImplmethod. | |
|
Yuta Kitamura
2014/12/24 06:31:18
nit: space between "traceImpl" and "method"
kouhei (in TOK)
2014/12/24 09:03:04
Done.
| |
| 1333 // We will report on CheckTraceMethod on traceImpl method. | |
| 1334 if (visitor.delegates_to_traceimpl()) | |
| 1335 return; | |
| 1336 | |
| 1306 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 1337 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
| 1307 it != parent->GetBases().end(); | 1338 it != parent->GetBases().end(); |
| 1308 ++it) { | 1339 ++it) { |
| 1309 if (!it->second.IsProperlyTraced()) | 1340 if (!it->second.IsProperlyTraced()) |
| 1310 ReportBaseRequiresTracing(parent, trace, it->first); | 1341 ReportBaseRequiresTracing(parent, trace, it->first); |
| 1311 } | 1342 } |
| 1312 | 1343 |
| 1313 for (RecordInfo::Fields::iterator it = parent->GetFields().begin(); | 1344 for (RecordInfo::Fields::iterator it = parent->GetFields().begin(); |
| 1314 it != parent->GetFields().end(); | 1345 it != parent->GetFields().end(); |
| 1315 ++it) { | 1346 ++it) { |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1887 | 1918 |
| 1888 private: | 1919 private: |
| 1889 BlinkGCPluginOptions options_; | 1920 BlinkGCPluginOptions options_; |
| 1890 }; | 1921 }; |
| 1891 | 1922 |
| 1892 } // namespace | 1923 } // namespace |
| 1893 | 1924 |
| 1894 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1925 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
| 1895 "blink-gc-plugin", | 1926 "blink-gc-plugin", |
| 1896 "Check Blink GC invariants"); | 1927 "Check Blink GC invariants"); |
| OLD | NEW |