Chromium Code Reviews| 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; |
| } |