| 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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 194 |
| 195 // Collect record declarations, including nested declarations. | 195 // Collect record declarations, including nested declarations. |
| 196 bool VisitCXXRecordDecl(CXXRecordDecl* record) { | 196 bool VisitCXXRecordDecl(CXXRecordDecl* record) { |
| 197 if (record->hasDefinition() && record->isCompleteDefinition()) | 197 if (record->hasDefinition() && record->isCompleteDefinition()) |
| 198 record_decls_.push_back(record); | 198 record_decls_.push_back(record); |
| 199 return true; | 199 return true; |
| 200 } | 200 } |
| 201 | 201 |
| 202 // Collect tracing method definitions, but don't traverse method bodies. | 202 // Collect tracing method definitions, but don't traverse method bodies. |
| 203 bool TraverseCXXMethodDecl(CXXMethodDecl* method) { | 203 bool TraverseCXXMethodDecl(CXXMethodDecl* method) { |
| 204 if (method->isThisDeclarationADefinition() && | 204 if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method)) |
| 205 Config::IsTraceMethod(method, nullptr)) | |
| 206 trace_decls_.push_back(method); | 205 trace_decls_.push_back(method); |
| 207 return true; | 206 return true; |
| 208 } | 207 } |
| 209 | 208 |
| 210 private: | 209 private: |
| 211 RecordVector record_decls_; | 210 RecordVector record_decls_; |
| 212 MethodVector trace_decls_; | 211 MethodVector trace_decls_; |
| 213 }; | 212 }; |
| 214 | 213 |
| 215 // This visitor checks that a finalizer method does not have invalid access to | 214 // This visitor checks that a finalizer method does not have invalid access to |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 it->second.MarkTraced(); | 376 it->second.MarkTraced(); |
| 378 } | 377 } |
| 379 } | 378 } |
| 380 | 379 |
| 381 QualType base = expr->getBaseType(); | 380 QualType base = expr->getBaseType(); |
| 382 if (!base->isPointerType()) | 381 if (!base->isPointerType()) |
| 383 return true; | 382 return true; |
| 384 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); | 383 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); |
| 385 if (decl) | 384 if (decl) |
| 386 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); | 385 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); |
| 387 if (expr->getMemberName().getAsString() == kTraceImplName) | 386 if (Config::IsTraceImplName(expr->getMemberName().getAsString())) |
| 388 delegates_to_traceimpl_ = true; | 387 delegates_to_traceimpl_ = true; |
| 389 return true; | 388 return true; |
| 390 } | 389 } |
| 391 | 390 |
| 392 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { | 391 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { |
| 393 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) | 392 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) |
| 394 return true; | 393 return true; |
| 395 | 394 |
| 396 if (expr->getMethodDecl()->getNameAsString() == kTraceImplName) { | 395 if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) { |
| 397 delegates_to_traceimpl_ = true; | 396 delegates_to_traceimpl_ = true; |
| 398 return true; | 397 return true; |
| 399 } | 398 } |
| 400 } | 399 } |
| 401 | 400 |
| 402 CheckTraceBaseCall(call); | 401 CheckTraceBaseCall(call); |
| 403 return true; | 402 return true; |
| 404 } | 403 } |
| 405 | 404 |
| 406 private: | 405 private: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 FoundField(finder.field()); | 459 FoundField(finder.field()); |
| 461 } | 460 } |
| 462 } | 461 } |
| 463 | 462 |
| 464 bool CheckTraceBaseCall(CallExpr* call) { | 463 bool CheckTraceBaseCall(CallExpr* call) { |
| 465 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); | 464 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); |
| 466 if (!callee) | 465 if (!callee) |
| 467 return false; | 466 return false; |
| 468 | 467 |
| 469 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); | 468 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); |
| 470 if (!fn || !Config::IsTraceMethod(fn, nullptr)) | 469 if (!fn || !Config::IsTraceMethod(fn)) |
| 471 return false; | 470 return false; |
| 472 | 471 |
| 473 if (trace_->getName() == kTraceImplName) { | 472 if (trace_->getName() == kTraceImplName) { |
| 474 if (fn->getName() != kTraceName) | 473 if (fn->getName() != kTraceName) |
| 475 return false; | 474 return false; |
| 475 } else if (trace_->getName() == kTraceAfterDispatchImplName) { |
| 476 if (fn->getName() != kTraceAfterDispatchName) |
| 477 return false; |
| 476 } else { | 478 } else { |
| 477 // Currently, a manually dispatched class cannot have mixin bases (having | 479 // Currently, a manually dispatched class cannot have mixin bases (having |
| 478 // one would add a vtable which we explicitly check against). This means | 480 // one would add a vtable which we explicitly check against). This means |
| 479 // that we can only make calls to a trace method of the same name. Revisit | 481 // that we can only make calls to a trace method of the same name. Revisit |
| 480 // this if our mixin/vtable assumption changes. | 482 // this if our mixin/vtable assumption changes. |
| 481 if (fn->getName() != trace_->getName()) | 483 if (fn->getName() != trace_->getName()) |
| 482 return false; | 484 return false; |
| 483 } | 485 } |
| 484 | 486 |
| 485 CXXRecordDecl* decl = 0; | 487 CXXRecordDecl* decl = 0; |
| (...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1306 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method); | 1308 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method); |
| 1307 } | 1309 } |
| 1308 return; | 1310 return; |
| 1309 } | 1311 } |
| 1310 | 1312 |
| 1311 CheckTraceOrDispatchMethod(parent, method); | 1313 CheckTraceOrDispatchMethod(parent, method); |
| 1312 } | 1314 } |
| 1313 | 1315 |
| 1314 // Determine what type of tracing method this is (dispatch or trace). | 1316 // Determine what type of tracing method this is (dispatch or trace). |
| 1315 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { | 1317 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { |
| 1316 bool isTraceAfterDispatch; | 1318 Config::TraceMethodType trace_type = Config::GetTraceMethodType(method); |
| 1317 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) { | 1319 if (trace_type != Config::TRACE_METHOD || |
| 1318 if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) { | 1320 !parent->GetTraceDispatchMethod()) { |
| 1319 CheckTraceMethod(parent, method, isTraceAfterDispatch); | 1321 CheckTraceMethod(parent, method, trace_type); |
| 1320 } | |
| 1321 // Dispatch methods are checked when we identify subclasses. | |
| 1322 } | 1322 } |
| 1323 // Dispatch methods are checked when we identify subclasses. |
| 1323 } | 1324 } |
| 1324 | 1325 |
| 1325 // Check an actual trace method. | 1326 // Check an actual trace method. |
| 1326 void CheckTraceMethod(RecordInfo* parent, | 1327 void CheckTraceMethod(RecordInfo* parent, |
| 1327 CXXMethodDecl* trace, | 1328 CXXMethodDecl* trace, |
| 1328 bool isTraceAfterDispatch) { | 1329 Config::TraceMethodType trace_type) { |
| 1329 // A trace method must not override any non-virtual trace methods. | 1330 // A trace method must not override any non-virtual trace methods. |
| 1330 if (!isTraceAfterDispatch) { | 1331 if (trace_type == Config::TRACE_METHOD) { |
| 1331 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 1332 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
| 1332 it != parent->GetBases().end(); | 1333 it != parent->GetBases().end(); |
| 1333 ++it) { | 1334 ++it) { |
| 1334 RecordInfo* base = it->second.info(); | 1335 RecordInfo* base = it->second.info(); |
| 1335 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) | 1336 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) |
| 1336 ReportOverriddenNonVirtualTrace(parent, trace, other); | 1337 ReportOverriddenNonVirtualTrace(parent, trace, other); |
| 1337 } | 1338 } |
| 1338 } | 1339 } |
| 1339 | 1340 |
| 1340 CheckTraceVisitor visitor(trace, parent); | 1341 CheckTraceVisitor visitor(trace, parent); |
| 1341 visitor.TraverseCXXMethodDecl(trace); | 1342 visitor.TraverseCXXMethodDecl(trace); |
| 1342 | 1343 |
| 1343 // Skip reporting if this trace method is a just delegate to | 1344 // Skip reporting if this trace method is a just delegate to |
| 1344 // traceImpl method. We will report on CheckTraceMethod on traceImpl method. | 1345 // traceImpl (or traceAfterDispatchImpl) method. We will report on |
| 1346 // CheckTraceMethod on traceImpl method. |
| 1345 if (visitor.delegates_to_traceimpl()) | 1347 if (visitor.delegates_to_traceimpl()) |
| 1346 return; | 1348 return; |
| 1347 | 1349 |
| 1348 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); | 1350 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); |
| 1349 it != parent->GetBases().end(); | 1351 it != parent->GetBases().end(); |
| 1350 ++it) { | 1352 ++it) { |
| 1351 if (!it->second.IsProperlyTraced()) | 1353 if (!it->second.IsProperlyTraced()) |
| 1352 ReportBaseRequiresTracing(parent, trace, it->first); | 1354 ReportBaseRequiresTracing(parent, trace, it->first); |
| 1353 } | 1355 } |
| 1354 | 1356 |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1939 | 1941 |
| 1940 private: | 1942 private: |
| 1941 BlinkGCPluginOptions options_; | 1943 BlinkGCPluginOptions options_; |
| 1942 }; | 1944 }; |
| 1943 | 1945 |
| 1944 } // namespace | 1946 } // namespace |
| 1945 | 1947 |
| 1946 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( | 1948 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( |
| 1947 "blink-gc-plugin", | 1949 "blink-gc-plugin", |
| 1948 "Check Blink GC invariants"); | 1950 "Check Blink GC invariants"); |
| OLD | NEW |