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 |