| Index: tools/clang/blink_gc_plugin/CheckTraceVisitor.cpp
 | 
| diff --git a/tools/clang/blink_gc_plugin/CheckTraceVisitor.cpp b/tools/clang/blink_gc_plugin/CheckTraceVisitor.cpp
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..c996ca7dd1480a76c65ddf12f3fd8d2215aa7009
 | 
| --- /dev/null
 | 
| +++ b/tools/clang/blink_gc_plugin/CheckTraceVisitor.cpp
 | 
| @@ -0,0 +1,399 @@
 | 
| +// Copyright 2015 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "CheckTraceVisitor.h"
 | 
| +
 | 
| +#include <vector>
 | 
| +
 | 
| +#include "Config.h"
 | 
| +
 | 
| +using namespace clang;
 | 
| +
 | 
| +CheckTraceVisitor::CheckTraceVisitor(CXXMethodDecl* trace,
 | 
| +                                     RecordInfo* info,
 | 
| +                                     RecordCache* cache)
 | 
| +    : trace_(trace),
 | 
| +      info_(info),
 | 
| +      cache_(cache),
 | 
| +      delegates_to_traceimpl_(false) {
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::delegates_to_traceimpl() const {
 | 
| +  return delegates_to_traceimpl_;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::VisitMemberExpr(MemberExpr* member) {
 | 
| +  // In weak callbacks, consider any occurrence as a correct usage.
 | 
| +  // TODO: We really want to require that isAlive is checked on manually
 | 
| +  // processed weak fields.
 | 
| +  if (IsWeakCallback()) {
 | 
| +    if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()))
 | 
| +      FoundField(field);
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::VisitCallExpr(CallExpr* call) {
 | 
| +  // In weak callbacks we don't check calls (see VisitMemberExpr).
 | 
| +  if (IsWeakCallback())
 | 
| +    return true;
 | 
| +
 | 
| +  Expr* callee = call->getCallee();
 | 
| +
 | 
| +  // Trace calls from a templated derived class result in a
 | 
| +  // DependentScopeMemberExpr because the concrete trace call depends on the
 | 
| +  // instantiation of any shared template parameters. In this case the call is
 | 
| +  // "unresolved" and we resort to comparing the syntactic type names.
 | 
| +  if (CXXDependentScopeMemberExpr* expr =
 | 
| +      dyn_cast<CXXDependentScopeMemberExpr>(callee)) {
 | 
| +    CheckCXXDependentScopeMemberExpr(call, expr);
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // A tracing call will have either a |visitor| or a |m_field| argument.
 | 
| +  // A registerWeakMembers call will have a |this| argument.
 | 
| +  if (call->getNumArgs() != 1)
 | 
| +    return true;
 | 
| +  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 (expr->getMemberName().getAsString() == kRegisterWeakMembersName)
 | 
| +      MarkAllWeakMembersTraced();
 | 
| +
 | 
| +    QualType base = expr->getBaseType();
 | 
| +    if (!base->isPointerType())
 | 
| +      return true;
 | 
| +    CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
 | 
| +    if (decl)
 | 
| +      CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
 | 
| +    if (Config::IsTraceImplName(expr->getMemberName().getAsString()))
 | 
| +      delegates_to_traceimpl_ = true;
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) {
 | 
| +    if (CheckTraceFieldMemberCall(expr) || CheckRegisterWeakMembers(expr))
 | 
| +      return true;
 | 
| +
 | 
| +    if (Config::IsTraceImplName(expr->getMethodDecl()->getNameAsString())) {
 | 
| +      delegates_to_traceimpl_ = true;
 | 
| +      return true;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  CheckTraceBaseCall(call);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::IsTraceCallName(const std::string& name) {
 | 
| +  if (trace_->getName() == kTraceImplName)
 | 
| +    return name == kTraceName;
 | 
| +  if (trace_->getName() == kTraceAfterDispatchImplName)
 | 
| +    return name == kTraceAfterDispatchName;
 | 
| +  // 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.
 | 
| +  return name == trace_->getName();
 | 
| +}
 | 
| +
 | 
| +CXXRecordDecl* CheckTraceVisitor::GetDependentTemplatedDecl(
 | 
| +    CXXDependentScopeMemberExpr* expr) {
 | 
| +  NestedNameSpecifier* qual = expr->getQualifier();
 | 
| +  if (!qual)
 | 
| +    return 0;
 | 
| +
 | 
| +  const Type* type = qual->getAsType();
 | 
| +  if (!type)
 | 
| +    return 0;
 | 
| +
 | 
| +  return RecordInfo::GetDependentTemplatedDecl(*type);
 | 
| +}
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +class FindFieldVisitor : public RecursiveASTVisitor<FindFieldVisitor> {
 | 
| + public:
 | 
| +  FindFieldVisitor();
 | 
| +  MemberExpr* member() const;
 | 
| +  FieldDecl* field() const;
 | 
| +  bool TraverseMemberExpr(MemberExpr* member);
 | 
| +
 | 
| + private:
 | 
| +  MemberExpr* member_;
 | 
| +  FieldDecl* field_;
 | 
| +};
 | 
| +
 | 
| +FindFieldVisitor::FindFieldVisitor()
 | 
| +    : member_(0),
 | 
| +      field_(0) {
 | 
| +}
 | 
| +
 | 
| +MemberExpr* FindFieldVisitor::member() const {
 | 
| +  return member_;
 | 
| +}
 | 
| +
 | 
| +FieldDecl* FindFieldVisitor::field() const {
 | 
| +  return field_;
 | 
| +}
 | 
| +
 | 
| +bool FindFieldVisitor::TraverseMemberExpr(MemberExpr* member) {
 | 
| +  if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) {
 | 
| +    member_ = member;
 | 
| +    field_ = field;
 | 
| +    return false;
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +void CheckTraceVisitor::CheckCXXDependentScopeMemberExpr(
 | 
| +    CallExpr* call,
 | 
| +    CXXDependentScopeMemberExpr* expr) {
 | 
| +  std::string fn_name = expr->getMember().getAsString();
 | 
| +
 | 
| +  // Check for VisitorDispatcher::trace(field) and
 | 
| +  // VisitorDispatcher::registerWeakMembers.
 | 
| +  if (!expr->isImplicitAccess()) {
 | 
| +    if (DeclRefExpr* base_decl = dyn_cast<DeclRefExpr>(expr->getBase())) {
 | 
| +      if (Config::IsVisitorDispatcherType(base_decl->getType())) {
 | 
| +        if (call->getNumArgs() == 1 && fn_name == kTraceName) {
 | 
| +          FindFieldVisitor finder;
 | 
| +          finder.TraverseStmt(call->getArg(0));
 | 
| +          if (finder.field())
 | 
| +            FoundField(finder.field());
 | 
| +
 | 
| +          return;
 | 
| +        } else if (call->getNumArgs() == 1 &&
 | 
| +                   fn_name == kRegisterWeakMembersName) {
 | 
| +          MarkAllWeakMembersTraced();
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  CXXRecordDecl* tmpl = GetDependentTemplatedDecl(expr);
 | 
| +  if (!tmpl)
 | 
| +    return;
 | 
| +
 | 
| +  // Check for Super<T>::trace(visitor)
 | 
| +  if (call->getNumArgs() == 1 && IsTraceCallName(fn_name)) {
 | 
| +    RecordInfo::Bases::iterator it = info_->GetBases().begin();
 | 
| +    for (; it != info_->GetBases().end(); ++it) {
 | 
| +      if (it->first->getName() == tmpl->getName())
 | 
| +        it->second.MarkTraced();
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  // Check for TraceIfNeeded<T>::trace(visitor, &field)
 | 
| +  if (call->getNumArgs() == 2 && fn_name == kTraceName &&
 | 
| +      tmpl->getName() == kTraceIfNeededName) {
 | 
| +    FindFieldVisitor finder;
 | 
| +    finder.TraverseStmt(call->getArg(1));
 | 
| +    if (finder.field())
 | 
| +      FoundField(finder.field());
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::CheckTraceBaseCall(CallExpr* call) {
 | 
| +  // 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* 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 (!callee_record)
 | 
| +    return false;
 | 
| +
 | 
| +  if (!IsTraceCallName(func_name))
 | 
| +    return false;
 | 
| +
 | 
| +  for (auto& base : info_->GetBases()) {
 | 
| +    // We want to deal with omitted trace() function in an intermediary
 | 
| +    // class in the class hierarchy, e.g.:
 | 
| +    //     class A : public GarbageCollected<A> { trace() { ... } };
 | 
| +    //     class B : public A { /* No trace(); have nothing to trace. */ };
 | 
| +    //     class C : public B { trace() { B::trace(visitor); } }
 | 
| +    // where, B::trace() is actually A::trace(), and in some cases we get
 | 
| +    // A as |callee_record| instead of B. We somehow need to mark B as
 | 
| +    // traced if we find A::trace() call.
 | 
| +    //
 | 
| +    // To solve this, here we keep going up the class hierarchy as long as
 | 
| +    // they are not required to have a trace method. The implementation is
 | 
| +    // a simple DFS, where |base_records| represents the set of base classes
 | 
| +    // we need to visit.
 | 
| +
 | 
| +    std::vector<CXXRecordDecl*> base_records;
 | 
| +    base_records.push_back(base.first);
 | 
| +
 | 
| +    while (!base_records.empty()) {
 | 
| +      CXXRecordDecl* base_record = base_records.back();
 | 
| +      base_records.pop_back();
 | 
| +
 | 
| +      if (base_record == callee_record) {
 | 
| +        // If we find a matching trace method, pretend the user has written
 | 
| +        // a correct trace() method of the base; in the example above, we
 | 
| +        // find A::trace() here and mark B as correctly traced.
 | 
| +        base.second.MarkTraced();
 | 
| +        return true;
 | 
| +      }
 | 
| +
 | 
| +      if (RecordInfo* base_info = cache_->Lookup(base_record)) {
 | 
| +        if (!base_info->RequiresTraceMethod()) {
 | 
| +          // If this base class is not required to have a trace method, then
 | 
| +          // the actual trace method may be defined in an ancestor.
 | 
| +          for (auto& inner_base : base_info->GetBases())
 | 
| +            base_records.push_back(inner_base.first);
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::CheckTraceFieldMemberCall(CXXMemberCallExpr* call) {
 | 
| +  return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
 | 
| +                             call->getRecordDecl(),
 | 
| +                             call->getArg(0));
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::CheckTraceFieldCall(
 | 
| +    const std::string& name,
 | 
| +    CXXRecordDecl* callee,
 | 
| +    Expr* arg) {
 | 
| +  if (name != kTraceName || !Config::IsVisitor(callee->getName()))
 | 
| +    return false;
 | 
| +
 | 
| +  FindFieldVisitor finder;
 | 
| +  finder.TraverseStmt(arg);
 | 
| +  if (finder.field())
 | 
| +    FoundField(finder.field());
 | 
| +
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::CheckRegisterWeakMembers(CXXMemberCallExpr* call) {
 | 
| +  CXXMethodDecl* fn = call->getMethodDecl();
 | 
| +  if (fn->getName() != kRegisterWeakMembersName)
 | 
| +    return false;
 | 
| +
 | 
| +  if (fn->isTemplateInstantiation()) {
 | 
| +    const TemplateArgumentList& args =
 | 
| +        *fn->getTemplateSpecializationInfo()->TemplateArguments;
 | 
| +    // The second template argument is the callback method.
 | 
| +    if (args.size() > 1 &&
 | 
| +        args[1].getKind() == TemplateArgument::Declaration) {
 | 
| +      if (FunctionDecl* callback =
 | 
| +          dyn_cast<FunctionDecl>(args[1].getAsDecl())) {
 | 
| +        if (callback->hasBody()) {
 | 
| +          CheckTraceVisitor nested_visitor(nullptr, info_, nullptr);
 | 
| +          nested_visitor.TraverseStmt(callback->getBody());
 | 
| +        }
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool CheckTraceVisitor::IsWeakCallback() const {
 | 
| +  return !trace_;
 | 
| +}
 | 
| +
 | 
| +void CheckTraceVisitor::MarkTraced(RecordInfo::Fields::iterator it) {
 | 
| +  // In a weak callback we can't mark strong fields as traced.
 | 
| +  if (IsWeakCallback() && !it->second.edge()->IsWeakMember())
 | 
| +    return;
 | 
| +  it->second.MarkTraced();
 | 
| +}
 | 
| +
 | 
| +void CheckTraceVisitor::FoundField(FieldDecl* field) {
 | 
| +  if (Config::IsTemplateInstantiation(info_->record())) {
 | 
| +    // Pointer equality on fields does not work for template instantiations.
 | 
| +    // The trace method refers to fields of the template definition which
 | 
| +    // are different from the instantiated fields that need to be traced.
 | 
| +    const std::string& name = field->getNameAsString();
 | 
| +    for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
 | 
| +         it != info_->GetFields().end();
 | 
| +         ++it) {
 | 
| +      if (it->first->getNameAsString() == name) {
 | 
| +        MarkTraced(it);
 | 
| +        break;
 | 
| +      }
 | 
| +    }
 | 
| +  } else {
 | 
| +    RecordInfo::Fields::iterator it = info_->GetFields().find(field);
 | 
| +    if (it != info_->GetFields().end())
 | 
| +      MarkTraced(it);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void CheckTraceVisitor::MarkAllWeakMembersTraced() {
 | 
| +  // 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.
 | 
| +  for (auto& field : info_->GetFields()) {
 | 
| +    if (field.second.edge()->IsWeakMember())
 | 
| +      field.second.MarkTraced();
 | 
| +  }
 | 
| +}
 | 
| 
 |