| 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 7dae3810150a394785d0f80835ba81534bccac30..85cf08671894c966f8c74c392c9bcf54aff0e473 100644
|
| --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
|
| +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
|
| @@ -201,8 +201,7 @@ class CollectVisitor : public RecursiveASTVisitor<CollectVisitor> {
|
|
|
| // Collect tracing method definitions, but don't traverse method bodies.
|
| bool TraverseCXXMethodDecl(CXXMethodDecl* method) {
|
| - if (method->isThisDeclarationADefinition() &&
|
| - Config::IsTraceMethod(method, nullptr))
|
| + if (method->isThisDeclarationADefinition() && Config::IsTraceMethod(method))
|
| trace_decls_.push_back(method);
|
| return true;
|
| }
|
| @@ -366,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.
|
| @@ -384,7 +388,7 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
|
| CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
|
| if (decl)
|
| CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
|
| - if (expr->getMemberName().getAsString() == kTraceImplName)
|
| + if (Config::IsTraceImplName(expr->getMemberName().getAsString()))
|
| delegates_to_traceimpl_ = true;
|
| return true;
|
| }
|
| @@ -393,7 +397,7 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
|
| if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr))
|
| return true;
|
|
|
| - if (expr->getMethodDecl()->getNameAsString() == kTraceImplName) {
|
| + if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) {
|
| delegates_to_traceimpl_ = true;
|
| return true;
|
| }
|
| @@ -404,7 +408,6 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
|
| }
|
|
|
| private:
|
| -
|
| CXXRecordDecl* GetDependentTemplatedDecl(CXXDependentScopeMemberExpr* expr) {
|
| NestedNameSpecifier* qual = expr->getQualifier();
|
| if (!qual)
|
| @@ -462,39 +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, nullptr))
|
| - 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".
|
| + 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 (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;
|
| }
|
|
|
| @@ -1313,21 +1364,20 @@ class BlinkGCPluginConsumer : public ASTConsumer {
|
|
|
| // Determine what type of tracing method this is (dispatch or trace).
|
| void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) {
|
| - bool isTraceAfterDispatch;
|
| - if (Config::IsTraceMethod(method, &isTraceAfterDispatch)) {
|
| - if (isTraceAfterDispatch || !parent->GetTraceDispatchMethod()) {
|
| - CheckTraceMethod(parent, method, isTraceAfterDispatch);
|
| - }
|
| - // Dispatch methods are checked when we identify subclasses.
|
| + Config::TraceMethodType trace_type = Config::GetTraceMethodType(method);
|
| + if (trace_type != Config::TRACE_METHOD ||
|
| + !parent->GetTraceDispatchMethod()) {
|
| + CheckTraceMethod(parent, method, trace_type);
|
| }
|
| + // Dispatch methods are checked when we identify subclasses.
|
| }
|
|
|
| // Check an actual trace method.
|
| void CheckTraceMethod(RecordInfo* parent,
|
| CXXMethodDecl* trace,
|
| - bool isTraceAfterDispatch) {
|
| + Config::TraceMethodType trace_type) {
|
| // A trace method must not override any non-virtual trace methods.
|
| - if (!isTraceAfterDispatch) {
|
| + if (trace_type == Config::TRACE_METHOD) {
|
| for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
|
| it != parent->GetBases().end();
|
| ++it) {
|
| @@ -1341,7 +1391,8 @@ class BlinkGCPluginConsumer : public ASTConsumer {
|
| visitor.TraverseCXXMethodDecl(trace);
|
|
|
| // Skip reporting if this trace method is a just delegate to
|
| - // traceImpl method. We will report on CheckTraceMethod on traceImpl method.
|
| + // traceImpl (or traceAfterDispatchImpl) method. We will report on
|
| + // CheckTraceMethod on traceImpl method.
|
| if (visitor.delegates_to_traceimpl())
|
| return;
|
|
|
|
|