Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(663)

Side by Side Diff: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp

Issue 960873002: Update from https://crrev.com/318214 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/android/adb_remote_setup.sh ('k') | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 return true; 358 return true;
360 } 359 }
361 360
362 // 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.
363 // A registerWeakMembers call will have a |this| argument. 362 // A registerWeakMembers call will have a |this| argument.
364 if (call->getNumArgs() != 1) 363 if (call->getNumArgs() != 1)
365 return true; 364 return true;
366 Expr* arg = call->getArg(0); 365 Expr* arg = call->getArg(0);
367 366
368 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
369 // If we find a call to registerWeakMembers which is unresolved we 373 // If we find a call to registerWeakMembers which is unresolved we
370 // unsoundly consider all weak members as traced. 374 // unsoundly consider all weak members as traced.
371 // 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.
372 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { 376 if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) {
373 for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); 377 for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
374 it != info_->GetFields().end(); 378 it != info_->GetFields().end();
375 ++it) { 379 ++it) {
376 if (it->second.edge()->IsWeakMember()) 380 if (it->second.edge()->IsWeakMember())
377 it->second.MarkTraced(); 381 it->second.MarkTraced();
378 } 382 }
379 } 383 }
380 384
381 QualType base = expr->getBaseType(); 385 QualType base = expr->getBaseType();
382 if (!base->isPointerType()) 386 if (!base->isPointerType())
383 return true; 387 return true;
384 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); 388 CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
385 if (decl) 389 if (decl)
386 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); 390 CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
387 if (expr->getMemberName().getAsString() == kTraceImplName) 391 if (Config::IsTraceImplName(expr->getMemberName().getAsString()))
388 delegates_to_traceimpl_ = true; 392 delegates_to_traceimpl_ = true;
389 return true; 393 return true;
390 } 394 }
391 395
392 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { 396 if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) {
393 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) 397 if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr))
394 return true; 398 return true;
395 399
396 if (expr->getMethodDecl()->getNameAsString() == kTraceImplName) { 400 if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) {
397 delegates_to_traceimpl_ = true; 401 delegates_to_traceimpl_ = true;
398 return true; 402 return true;
399 } 403 }
400 } 404 }
401 405
402 CheckTraceBaseCall(call); 406 CheckTraceBaseCall(call);
403 return true; 407 return true;
404 } 408 }
405 409
406 private: 410 private:
407
408 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { 411 CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) {
409 NestedNameSpecifier* qual = expr->getQualifier(); 412 NestedNameSpecifier* qual = expr->getQualifier();
410 if (!qual) 413 if (!qual)
411 return 0; 414 return 0;
412 415
413 const Type* type = qual->getAsType(); 416 const Type* type = qual->getAsType();
414 if (!type) 417 if (!type)
415 return 0; 418 return 0;
416 419
417 return RecordInfo::GetDependentTemplatedDecl(*type); 420 return RecordInfo::GetDependentTemplatedDecl(*type);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 if (call->getNumArgs() == 2 && fn_name == kTraceName && 458 if (call->getNumArgs() == 2 && fn_name == kTraceName &&
456 tmpl->getName() == kTraceIfNeededName) { 459 tmpl->getName() == kTraceIfNeededName) {
457 FindFieldVisitor finder; 460 FindFieldVisitor finder;
458 finder.TraverseStmt(call->getArg(1)); 461 finder.TraverseStmt(call->getArg(1));
459 if (finder.field()) 462 if (finder.field())
460 FoundField(finder.field()); 463 FoundField(finder.field());
461 } 464 }
462 } 465 }
463 466
464 bool CheckTraceBaseCall(CallExpr* call) { 467 bool CheckTraceBaseCall(CallExpr* call) {
465 MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); 468 // Checks for "Base::trace(visitor)"-like calls.
466 if (!callee)
467 return false;
468 469
469 FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); 470 // Checking code for these two variables is shared among MemberExpr* case
470 if (!fn || !Config::IsTraceMethod(fn, nullptr)) 471 // and UnresolvedMemberCase* case below.
471 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".
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 }
472 526
473 if (trace_->getName() == kTraceImplName) { 527 if (trace_->getName() == kTraceImplName) {
474 if (fn->getName() != kTraceName) 528 if (func_name != kTraceName)
529 return false;
530 } else if (trace_->getName() == kTraceAfterDispatchImplName) {
531 if (func_name != kTraceAfterDispatchName)
475 return false; 532 return false;
476 } else { 533 } else {
477 // Currently, a manually dispatched class cannot have mixin bases (having 534 // Currently, a manually dispatched class cannot have mixin bases (having
478 // 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
479 // 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
480 // this if our mixin/vtable assumption changes. 537 // this if our mixin/vtable assumption changes.
481 if (fn->getName() != trace_->getName()) 538 if (func_name != trace_->getName())
482 return false; 539 return false;
483 } 540 }
484 541
485 CXXRecordDecl* decl = 0; 542 if (!callee_record)
486 if (callee && callee->hasQualifier()) { 543 return false;
487 if (const Type* type = callee->getQualifier()->getAsType()) 544 RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record);
488 decl = type->getAsCXXRecordDecl(); 545 if (iter == info_->GetBases().end())
489 }
490 if (!decl)
491 return false; 546 return false;
492 547
493 RecordInfo::Bases::iterator it = info_->GetBases().find(decl); 548 iter->second.MarkTraced();
494 if (it != info_->GetBases().end()) {
495 it->second.MarkTraced();
496 }
497
498 return true; 549 return true;
499 } 550 }
500 551
501 bool CheckTraceFieldCall(CXXMemberCallExpr* call) { 552 bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
502 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), 553 return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
503 call->getRecordDecl(), 554 call->getRecordDecl(),
504 call->getArg(0)); 555 call->getArg(0));
505 } 556 }
506 557
507 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { 558 bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) {
(...skipping 798 matching lines...) Expand 10 before | Expand all | Expand 10 after
1306 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method); 1357 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method);
1307 } 1358 }
1308 return; 1359 return;
1309 } 1360 }
1310 1361
1311 CheckTraceOrDispatchMethod(parent, method); 1362 CheckTraceOrDispatchMethod(parent, method);
1312 } 1363 }
1313 1364
1314 // Determine what type of tracing method this is (dispatch or trace). 1365 // Determine what type of tracing method this is (dispatch or trace).
1315 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) { 1366 void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) {
1316 bool isTraceAfterDispatch; 1367 Config::TraceMethodType trace_type = Config::GetTraceMethodType(method);
1317 if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) { 1368 if (trace_type != Config::TRACE_METHOD ||
1318 if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) { 1369 !parent->GetTraceDispatchMethod()) {
1319 CheckTraceMethod(parent, method, isTraceAfterDispatch); 1370 CheckTraceMethod(parent, method, trace_type);
1320 }
1321 // Dispatch methods are checked when we identify subclasses.
1322 } 1371 }
1372 // Dispatch methods are checked when we identify subclasses.
1323 } 1373 }
1324 1374
1325 // Check an actual trace method. 1375 // Check an actual trace method.
1326 void CheckTraceMethod(RecordInfo* parent, 1376 void CheckTraceMethod(RecordInfo* parent,
1327 CXXMethodDecl* trace, 1377 CXXMethodDecl* trace,
1328 bool isTraceAfterDispatch) { 1378 Config::TraceMethodType trace_type) {
1329 // A trace method must not override any non-virtual trace methods. 1379 // A trace method must not override any non-virtual trace methods.
1330 if (!isTraceAfterDispatch) { 1380 if (trace_type == Config::TRACE_METHOD) {
1331 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1381 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1332 it != parent->GetBases().end(); 1382 it != parent->GetBases().end();
1333 ++it) { 1383 ++it) {
1334 RecordInfo* base = it->second.info(); 1384 RecordInfo* base = it->second.info();
1335 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace()) 1385 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
1336 ReportOverriddenNonVirtualTrace(parent, trace, other); 1386 ReportOverriddenNonVirtualTrace(parent, trace, other);
1337 } 1387 }
1338 } 1388 }
1339 1389
1340 CheckTraceVisitor visitor(trace, parent); 1390 CheckTraceVisitor visitor(trace, parent);
1341 visitor.TraverseCXXMethodDecl(trace); 1391 visitor.TraverseCXXMethodDecl(trace);
1342 1392
1343 // Skip reporting if this trace method is a just delegate to 1393 // Skip reporting if this trace method is a just delegate to
1344 // traceImpl method. We will report on CheckTraceMethod on traceImpl method. 1394 // traceImpl (or traceAfterDispatchImpl) method. We will report on
1395 // CheckTraceMethod on traceImpl method.
1345 if (visitor.delegates_to_traceimpl()) 1396 if (visitor.delegates_to_traceimpl())
1346 return; 1397 return;
1347 1398
1348 for (RecordInfo::Bases::iterator it = parent->GetBases().begin(); 1399 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
1349 it != parent->GetBases().end(); 1400 it != parent->GetBases().end();
1350 ++it) { 1401 ++it) {
1351 if (!it->second.IsProperlyTraced()) 1402 if (!it->second.IsProperlyTraced())
1352 ReportBaseRequiresTracing(parent, trace, it->first); 1403 ReportBaseRequiresTracing(parent, trace, it->first);
1353 } 1404 }
1354 1405
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
1939 1990
1940 private: 1991 private:
1941 BlinkGCPluginOptions options_; 1992 BlinkGCPluginOptions options_;
1942 }; 1993 };
1943 1994
1944 } // namespace 1995 } // namespace
1945 1996
1946 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 1997 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1947 "blink-gc-plugin", 1998 "blink-gc-plugin",
1948 "Check Blink GC invariants"); 1999 "Check Blink GC invariants");
OLDNEW
« no previous file with comments | « tools/android/adb_remote_setup.sh ('k') | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698