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 43fbcf83d5fe1ab6bb1e45edf5b44f7e3c970300..9504eecc2e38fd3ef043d161260922893fd6d7f2 100644 |
| --- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
| +++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp |
| @@ -307,70 +307,175 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
| CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info) |
| : trace_(trace), info_(info) {} |
| - // Allow recursive traversal by using VisitMemberExpr. |
| bool VisitMemberExpr(MemberExpr* member) { |
| - // If this member expression references a field decl, mark it as traced. |
| - if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) { |
| - if (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 string& name = field->getNameAsString(); |
| + // 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 VisitCallExpr(CallExpr* call) { |
| + // In weak callbacks we don't check calls (see VisitMemberExpr). |
| + if (IsWeakCallback()) |
| + 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* callee = call->getCallee(); |
| + Expr* arg = call->getArg(0); |
| + |
| + if (CXXDependentScopeMemberExpr* expr = |
| + dyn_cast<CXXDependentScopeMemberExpr>(callee)) { |
| + CheckCXXDependentScopeMemberExpr(expr); |
| + return true; |
| + } |
| + |
| + if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) { |
| + // 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. |
| + if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) { |
| for (RecordInfo::Fields::iterator it = info_->GetFields().begin(); |
| it != info_->GetFields().end(); |
| ++it) { |
| - if (it->first->getNameAsString() == name) { |
| - MarkTraced(it); |
| - break; |
| - } |
| + if (it->second.edge()->IsWeakMember()) |
| + it->second.MarkTraced(); |
| } |
| - } else { |
| - RecordInfo::Fields::iterator it = info_->GetFields().find(field); |
| - if (it != info_->GetFields().end()) |
| - MarkTraced(it); |
| } |
| + |
| + QualType base = expr->getBaseType(); |
| + if (!base->isPointerType()) |
| + return true; |
| + CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl(); |
| + if (decl) |
| + CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg); |
| return true; |
| } |
| - // If this is a weak callback function we only check field tracing. |
| + if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) { |
| + if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr)) |
| + return true; |
| + } |
| + |
| + CheckTraceBaseCall(call); |
| + return true; |
| + } |
| + |
| + private: |
| + |
| + // Trace calls from a templated derived class to its templated super class |
| + // result in a DependentScopeMemberExpr because the concrete class depends on |
| + // the instantiation of any shared template parameters. In this case we |
| + // compare the type names. |
| + void CheckCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr* member) { |
| if (IsWeakCallback()) |
| - return true; |
| + return; |
| - // For method calls, check tracing of bases and other special GC methods. |
| - if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) { |
| - const string& name = fn->getNameAsString(); |
| - // Check weak callbacks. |
| - if (name == kRegisterWeakMembersName) { |
| - 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(info_); |
| - nested_visitor.TraverseStmt(callback->getBody()); |
| - } |
| - } |
| - } |
| - } |
| - return true; |
| - } |
| + // It is unknown if the member resolves to a method so we string compare. |
|
haraken
2014/07/31 15:37:11
we string compare => we compare strings
|
| + if (member->getMember().getAsString() != trace_->getName()) |
| + return; |
| + |
| + NestedNameSpecifier* qual = member->getQualifier(); |
| + if (!qual) |
| + return; |
| + |
| + const Type* type = qual->getAsType(); |
| + if (!type) |
| + return; |
| + |
| + const TemplateSpecializationType* tmpl_type = |
| + type->getAs<TemplateSpecializationType>(); |
| + if (!tmpl_type) |
| + return; |
| + |
| + TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); |
| + if (!tmpl_decl) |
| + return; |
| + |
| + CXXRecordDecl* rec = dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); |
| + if (!rec) |
| + return; |
| + |
| + RecordInfo::Bases::iterator it; |
| + for (it = info_->GetBases().begin(); it != info_->GetBases().end(); ++it) { |
| + if (it->first->getName() == rec->getName()) |
| + it->second.MarkTraced(); |
| + } |
| + } |
| + |
| + bool CheckTraceBaseCall(CallExpr* call) { |
| + MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee()); |
| + if (!callee) |
| + return false; |
| + |
| + FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl()); |
| + if (!fn || !Config::IsTraceMethod(fn)) |
| + return false; |
| + |
| + // 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()) |
| + return false; |
| + |
| + CXXRecordDecl* decl = 0; |
| + if (callee && callee->hasQualifier()) { |
| + if (const Type* type = callee->getQualifier()->getAsType()) |
| + decl = type->getAsCXXRecordDecl(); |
| + } |
| + if (!decl) |
| + return false; |
| + |
| + RecordInfo::Bases::iterator it = info_->GetBases().find(decl); |
| + if (it != info_->GetBases().end()) { |
| + it->second.MarkTraced(); |
| + } |
| + |
| + return true; |
| + } |
| + |
| + bool CheckTraceFieldCall(CXXMemberCallExpr* call) { |
| + return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(), |
| + call->getRecordDecl(), |
| + call->getArg(0)); |
| + } |
| + |
| + bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) { |
| + if (name != kTraceName || !Config::IsVisitor(callee->getName())) |
| + return false; |
| - // 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 (Config::IsTraceMethod(fn) && |
| - fn->getName() == trace_->getName() && |
| - member->hasQualifier()) { |
| - if (const Type* type = member->getQualifier()->getAsType()) { |
| - if (CXXRecordDecl* decl = type->getAsCXXRecordDecl()) { |
| - RecordInfo::Bases::iterator it = info_->GetBases().find(decl); |
| - if (it != info_->GetBases().end()) |
| - it->second.MarkTraced(); |
| + FindFieldVisitor finder; |
| + finder.TraverseStmt(arg); |
| + if (finder.field()) |
| + FoundField(finder.field()); |
| + |
| + return true; |
| + } |
| + |
| + bool 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(info_); |
| + nested_visitor.TraverseStmt(callback->getBody()); |
| } |
| } |
| } |
| @@ -378,7 +483,24 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
| return true; |
| } |
| - private: |
| + class FindFieldVisitor : public RecursiveASTVisitor<FindFieldVisitor> { |
| + public: |
| + FindFieldVisitor() : member_(0), field_(0) {} |
| + MemberExpr* member() const { return member_; } |
| + FieldDecl* field() const { return field_; } |
| + bool TraverseMemberExpr(MemberExpr* member) { |
| + if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) { |
| + member_ = member; |
| + field_ = field; |
| + return false; |
| + } |
| + return true; |
| + } |
| + private: |
| + MemberExpr* member_; |
| + FieldDecl* field_; |
| + }; |
| + |
| // Nested checking for weak callbacks. |
| CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {} |
| @@ -391,6 +513,27 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> { |
| it->second.MarkTraced(); |
| } |
| + void FoundField(FieldDecl* field) { |
| + if (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 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); |
| + } |
| + } |
| + |
| CXXMethodDecl* trace_; |
| RecordInfo* info_; |
| }; |
| @@ -574,8 +717,7 @@ class BlinkGCPluginConsumer : public ASTConsumer { |
| options_(options), |
| json_(0) { |
| - // Only check structures in the blink, blink and WebKit namespaces. |
| - options_.checked_namespaces.insert("blink"); |
| + // Only check structures in the blink and WebKit namespaces. |
| options_.checked_namespaces.insert("blink"); |
| options_.checked_namespaces.insert("WebKit"); |