Index: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
index 2924fd304fac91fe76adc32866d7c371b0f42c57..85cf08671894c966f8c74c392c9bcf54aff0e473 100644 |
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
@@ -365,6 +365,11 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
Expr* arg = call->getArg(0); |
if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { |
+ // This could be a trace call of a base class, as explained in the |
+ // comments of CheckTraceBaseCall(). |
+ if (CheckTraceBaseCall(call)) |
+ return true; |
+ |
// If we find a call to registerWeakMembers which is unresolved we |
// unsoundly consider all weak members as traced. |
// TODO: Find out how to validate weak member tracing for unresolved call. |
@@ -403,7 +408,6 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
} |
private: |
- |
CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) { |
NestedNameSpecifier* qual = expr->getQualifier(); |
if (!qual) |
@@ -461,42 +465,87 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
} |
bool CheckTraceBaseCall(CallExpr* call) { |
- MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); |
- if (!callee) |
- return false; |
+ // Checks for "Base::trace(visitor)"-like calls. |
+ |
+ // Checking code for these two variables is shared among MemberExpr* case |
+ // and UnresolvedMemberCase* case below. |
+ // |
+ // For example, if we've got "Base::trace(visitor)" as |call|, |
+ // callee_record will be "Base", and func_name will be "trace". |
+ CXXRecordDecl* callee_record = nullptr; |
+ std::string func_name; |
+ |
+ if (MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee())) { |
+ if (!callee->hasQualifier()) |
+ return false; |
- FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); |
- if (!fn || !Config::IsTraceMethod(fn)) |
- return false; |
+ FunctionDecl* trace_decl = |
+ dyn_cast<FunctionDecl>(callee->getMemberDecl()); |
+ if (!trace_decl || !Config::IsTraceMethod(trace_decl)) |
+ return false; |
+ |
+ const Type* type = callee->getQualifier()->getAsType(); |
+ if (!type) |
+ return false; |
+ |
+ callee_record = type->getAsCXXRecordDecl(); |
+ func_name = trace_decl->getName(); |
+ } else if (UnresolvedMemberExpr* callee = |
+ dyn_cast<UnresolvedMemberExpr>(call->getCallee())) { |
+ // Callee part may become unresolved if the type of the argument |
+ // ("visitor") is a template parameter and the called function is |
+ // overloaded (i.e. trace(Visitor*) and |
+ // trace(InlinedGlobalMarkingVisitor)). |
+ // |
+ // Here, we try to find a function that looks like trace() from the |
+ // candidate overloaded functions, and if we find one, we assume it is |
+ // called here. |
+ |
+ CXXMethodDecl* trace_decl = nullptr; |
+ for (NamedDecl* named_decl : callee->decls()) { |
+ if (CXXMethodDecl* method_decl = dyn_cast<CXXMethodDecl>(named_decl)) { |
+ if (Config::IsTraceMethod(method_decl)) { |
+ trace_decl = method_decl; |
+ break; |
+ } |
+ } |
+ } |
+ if (!trace_decl) |
+ return false; |
+ |
+ // 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.
|
+ if (call->getNumArgs() != 1) |
+ return false; |
+ DeclRefExpr* arg = dyn_cast<DeclRefExpr>(call->getArg(0)); |
+ if (!arg || arg->getNameInfo().getAsString() != kVisitorVarName) |
+ return false; |
+ |
+ callee_record = trace_decl->getParent(); |
+ func_name = callee->getMemberName().getAsString(); |
+ } |
if (trace_->getName() == kTraceImplName) { |
- if (fn->getName() != kTraceName) |
+ if (func_name != kTraceName) |
return false; |
} else if (trace_->getName() == kTraceAfterDispatchImplName) { |
- if (fn->getName() != kTraceAfterDispatchName) |
+ if (func_name != kTraceAfterDispatchName) |
return false; |
} else { |
// Currently, a manually dispatched class cannot have mixin bases (having |
// one would add a vtable which we explicitly check against). This means |
// that we can only make calls to a trace method of the same name. Revisit |
// this if our mixin/vtable assumption changes. |
- if (fn->getName() != trace_->getName()) |
+ if (func_name != trace_->getName()) |
return false; |
} |
- CXXRecordDecl* decl = 0; |
- if (callee && callee->hasQualifier()) { |
- if (const Type* type = callee->getQualifier()->getAsType()) |
- decl = type->getAsCXXRecordDecl(); |
- } |
- if (!decl) |
+ if (!callee_record) |
+ return false; |
+ RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record); |
+ if (iter == info_->GetBases().end()) |
return false; |
- RecordInfo::Bases::iterator it = info_->GetBases().find(decl); |
- if (it != info_->GetBases().end()) { |
- it->second.MarkTraced(); |
- } |
- |
+ iter->second.MarkTraced(); |
return true; |
} |