Chromium Code Reviews| Index: tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp |
| diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp |
| index 3c39350d311c0d1c6c26b1268a6b55d43ed8f0f8..0edb736f870842734aa76965fa1a80d3f7ca1b51 100644 |
| --- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp |
| +++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp |
| @@ -62,6 +62,14 @@ const clang::ast_matchers::internal:: |
| VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> |
| unresolvedMemberExpr; |
| +const clang::ast_matchers::internal:: |
| + VariadicDynCastAllOfMatcher<clang::Expr, clang::DependentScopeDeclRefExpr> |
| + dependentScopeDeclRefExpr; |
| + |
| +const clang::ast_matchers::internal:: |
| + VariadicDynCastAllOfMatcher<clang::Expr, clang::CXXDependentScopeMemberExpr> |
| + cxxDependentScopeMemberExpr; |
| + |
| AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { |
| return Node.isOverloadedOperator(); |
| } |
| @@ -165,6 +173,35 @@ AST_MATCHER_P(clang::CXXMethodDecl, |
| return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder); |
| } |
| +// Matches |T::m| and/or |x->T::m| and/or |x->m| CXXDependentScopeMemberExpr |
| +// if member |m| comes from a type that matches the InnerMatcher. |
| +AST_MATCHER_P( |
| + clang::CXXDependentScopeMemberExpr, |
| + hasMemberFromType, |
| + clang::ast_matchers::internal::Matcher<clang::QualType>, |
| + InnerMatcher) { |
| + // Given |T::m| and/or |x->T::m| and/or |x->m| ... |
| + if (clang::NestedNameSpecifier* nestedNameSpecifier = Node.getQualifier()) { |
| + // ... if |T| is present, then InnerMatcher has to match |T|. |
| + clang::QualType qualType(nestedNameSpecifier->getAsType(), 0); |
| + return InnerMatcher.matches(qualType, Finder, Builder); |
| + } else { |
| + // ... if there is no |T|, then InnerMatcher has to match the type of |x|. |
| + clang::Expr* base_expr = Node.isImplicitAccess() ? nullptr : Node.getBase(); |
| + return base_expr && InnerMatcher.matches( |
| + base_expr->getType(), Finder, Builder); |
| + } |
| +} |
| + |
| +// Matches |const Class<T>&| QualType if InnerMatcher matches |Class<T>|. |
| +AST_MATCHER_P(clang::QualType, |
| + hasBaseType, |
| + clang::ast_matchers::internal::Matcher<clang::Type>, |
| + InnerMatcher) { |
| + const clang::Type* type = Node.getTypePtrOrNull(); |
| + return type && InnerMatcher.matches(*type, Finder, Builder); |
| +} |
| + |
| bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl, |
| const char* class_name) { |
| if (decl.getParent()->getQualifiedNameAsString() == class_name) |
| @@ -531,6 +568,24 @@ struct TargetNodeTraits<clang::DeclRefExpr> { |
| }; |
| template <> |
| +struct TargetNodeTraits<clang::DependentScopeDeclRefExpr> { |
| + static clang::SourceLocation GetLoc( |
| + const clang::DependentScopeDeclRefExpr& expr) { |
| + return expr.getLocation(); |
| + } |
| + static const char* GetName() { return "expr"; } |
| +}; |
| + |
| +template <> |
| +struct TargetNodeTraits<clang::CXXDependentScopeMemberExpr> { |
| + static clang::SourceLocation GetLoc( |
| + const clang::CXXDependentScopeMemberExpr& expr) { |
| + return expr.getMemberLoc(); |
| + } |
| + static const char* GetName() { return "expr"; } |
| +}; |
| + |
| +template <> |
| struct TargetNodeTraits<clang::CXXCtorInitializer> { |
| static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) { |
| assert(init.isWritten()); |
| @@ -677,10 +732,39 @@ clang::DeclarationName GetUnresolvedName( |
| } |
| clang::DeclarationName GetUnresolvedName( |
| + const clang::DependentScopeDeclRefExpr& expr) { |
| + return expr.getDeclName(); |
| +} |
| + |
| +clang::DeclarationName GetUnresolvedName( |
| + const clang::CXXDependentScopeMemberExpr& expr) { |
| + return expr.getMember(); |
| +} |
| + |
| +clang::DeclarationName GetUnresolvedName( |
| const clang::UnresolvedUsingValueDecl& decl) { |
| return decl.getDeclName(); |
| } |
| +// Returns whether |expr_node| is used as a callee in the AST (i.e. if |
| +// |expr_node| needs to resolve to a method or a function). |
| +bool IsCallee(const clang::Expr& expr, clang::ASTContext& context) { |
| + auto matcher = stmt(hasParent(callExpr(callee(equalsNode(&expr))))); |
| + return IsMatching(matcher, expr, context); |
| +} |
| + |
| +// Returns whether |decl| will be used as a callee in the AST (i.e. if the value |
| +// brought by the using declaration will resolve to a method or a function). |
| +bool IsCallee(const clang::UnresolvedUsingValueDecl& /* decl */, |
| + clang::ASTContext& /* context */) { |
| + // Heuristic - looking only at the shape of AST, let's assume that |using |
|
dcheng
2016/12/01 07:15:06
Nit: perhaps refine this comment to say that from
Łukasz Anforowicz
2016/12/01 18:26:57
Done.
|
| + // Base::foo| refers to a method. This heuristic can be refined by also |
| + // looking at the name of |decl| (this is done both for |
| + // UnresolvedUsingValueDecl and for clang::Expr in |
| + // GuessNameForUnresolvedDependentNode method). |
| + return true; |
| +} |
| + |
| template <typename TargetNode> |
| class UnresolvedRewriterBase : public RewriterBase<TargetNode> { |
| public: |
| @@ -690,13 +774,18 @@ class UnresolvedRewriterBase : public RewriterBase<TargetNode> { |
| : RewriterBase<TargetNode>(replacements) {} |
| void run(const MatchFinder::MatchResult& result) override { |
| - const TargetNode& expr = Base::GetTargetNode(result); |
| - llvm::StringRef old_name = GetUnresolvedName(expr).getAsString(); |
| + const TargetNode& node = Base::GetTargetNode(result); |
| + |
| + // Make sure there is an old name + extract the old name. |
| + clang::IdentifierInfo* info = GetUnresolvedName(node).getAsIdentifierInfo(); |
| + if (!info) |
| + return; |
| + llvm::StringRef old_name = info->getName(); |
| + |
| + // Try to guess a new name. |
| std::string new_name; |
| - if (GuessNameForUnresolvedDependentNode(expr, *result.Context, old_name, |
| - new_name)) { |
| + if (GuessNameForUnresolvedDependentNode(node, *result.Context, new_name)) |
| Base::AddReplacement(result, old_name, std::move(new_name)); |
| - } |
| } |
| private: |
| @@ -706,13 +795,31 @@ class UnresolvedRewriterBase : public RewriterBase<TargetNode> { |
| // a specific decl until template instantiation - at the point of rename, one |
| // cannot tell whether the node will eventually resolve to a field / method / |
| // constant / etc. |
| + // |
| + // The method returns false if no renaming should be done. |
| + // Otherwise the method returns true and sets |new_name|. |
| bool GuessNameForUnresolvedDependentNode(const TargetNode& node, |
| clang::ASTContext& context, |
| - llvm::StringRef old_name, |
| std::string& new_name) { |
| + // Verify that we have the kind of name we can rename. |
| + clang::DeclarationName decl_name = GetUnresolvedName(node); |
| + switch (decl_name.getNameKind()) { |
| + // Do not rewrite this: |
| + // return operator T*(); |
| + // into this: |
| + // return Operator type - parameter - 0 - 0 * T * (); |
| + case clang::DeclarationName::NameKind::CXXConversionFunctionName: |
| + case clang::DeclarationName::NameKind::CXXOperatorName: |
| + case clang::DeclarationName::NameKind::CXXLiteralOperatorName: |
| + return false; |
| + default: |
| + break; |
| + } |
| + llvm::StringRef old_name = decl_name.getAsIdentifierInfo()->getName(); |
| + |
| // |m_fieldName| -> |field_name_|. |
| if (old_name.startswith(kBlinkFieldPrefix)) { |
| - std::string field_name = old_name.str().substr(strlen(kBlinkFieldPrefix)); |
| + std::string field_name = old_name.substr(strlen(kBlinkFieldPrefix)); |
| if (field_name.find('_') == std::string::npos) { |
| new_name = CamelCaseToUnderscoreCase(field_name) + "_"; |
| return true; |
| @@ -720,10 +827,10 @@ class UnresolvedRewriterBase : public RewriterBase<TargetNode> { |
| } |
| // |T::myMethod(...)| -> |T::MyMethod(...)|. |
| - if ((old_name.find('_') == std::string::npos) && |
| + if ((old_name.find('_') == std::string::npos) && IsCallee(node, context) && |
| !IsBlacklistedFunctionOrMethodName(old_name)) { |
| new_name = old_name; |
| - new_name[0] = clang::toUppercase(new_name[0]); |
| + new_name[0] = clang::toUppercase(old_name[0]); |
| return true; |
| } |
| @@ -742,6 +849,12 @@ using UnresolvedDependentMemberRewriter = |
| using UnresolvedUsingValueDeclRewriter = |
| UnresolvedRewriterBase<clang::UnresolvedUsingValueDecl>; |
| +using DependentScopeDeclRefExprRewriter = |
| + UnresolvedRewriterBase<clang::DependentScopeDeclRefExpr>; |
| + |
| +using CXXDependentScopeMemberExprRewriter = |
| + UnresolvedRewriterBase<clang::CXXDependentScopeMemberExpr>; |
| + |
| } // namespace |
| static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
| @@ -1068,6 +1181,62 @@ int main(int argc, const char* argv[]) { |
| UsingDeclRewriter using_decl_rewriter(&replacements); |
| match_finder.addMatcher(using_decl_matcher, &using_decl_rewriter); |
| + // Matches any QualType that refers to a blink type: |
| + // - const blink::Foo& |
| + // - blink::Foo* |
| + // - blink::Foo<T> |
| + // - ... |
| + // TODO(lukasza): The matchers below can be simplified after |
| + // https://llvm.org/bugs/show_bug.cgi?id=30331 is fixed. |
| + // Simplified matchers: |
| + // auto blink_qual_type_base_matcher = |
| + // qualType(hasDeclaration(in_blink_namespace)); |
| + // auto blink_qual_type_matcher = qualType(anyOf( |
| + // blink_qual_type_base_matcher, |
| + // pointsTo(blink_qual_type_base_matcher), |
| + // references(blink_qual_type_base_matcher))); |
| + auto blink_qual_type_bug_workaround_matcher1 = hasBaseType( |
| + anyOf(enumType(hasDeclaration(in_blink_namespace)), |
| + recordType(hasDeclaration(in_blink_namespace)), |
| + templateSpecializationType(hasDeclaration(in_blink_namespace)), |
| + templateTypeParmType(hasDeclaration(in_blink_namespace)), |
| + typedefType(hasDeclaration(in_blink_namespace)))); |
| + auto blink_qual_type_base_matcher = |
| + qualType(anyOf(blink_qual_type_bug_workaround_matcher1, |
| + hasBaseType(elaboratedType( |
| + namesType(blink_qual_type_bug_workaround_matcher1))))); |
| + auto blink_qual_type_matcher = |
| + qualType(anyOf(blink_qual_type_base_matcher, pointsTo(in_blink_namespace), |
| + references(in_blink_namespace))); |
| + |
| + // Template-dependent decl lookup ======== |
| + // Given |
| + // template <typename T> void f() { T::foo(); } |
| + // matches |T::foo|. |
| + auto dependent_scope_decl_ref_expr_matcher = |
| + expr(id("expr", dependentScopeDeclRefExpr(has(nestedNameSpecifier( |
| + specifiesType(blink_qual_type_matcher)))))); |
| + DependentScopeDeclRefExprRewriter dependent_scope_decl_ref_expr_rewriter( |
| + &replacements); |
| + match_finder.addMatcher(dependent_scope_decl_ref_expr_matcher, |
| + &dependent_scope_decl_ref_expr_rewriter); |
| + |
| + // Template-dependent member lookup ======== |
| + // Given |
| + // template <typename T> |
| + // class Foo { |
| + // void f() { T::foo(); } |
| + // void g(T x) { x.bar(); } |
| + // }; |
| + // matches |T::foo| and |x.bar|. |
| + auto cxx_dependent_scope_member_expr_matcher = expr(id( |
| + "expr", |
| + cxxDependentScopeMemberExpr(hasMemberFromType(blink_qual_type_matcher)))); |
| + CXXDependentScopeMemberExprRewriter cxx_dependent_scope_member_expr_rewriter( |
| + &replacements); |
| + match_finder.addMatcher(cxx_dependent_scope_member_expr_matcher, |
| + &cxx_dependent_scope_member_expr_rewriter); |
| + |
| std::unique_ptr<clang::tooling::FrontendActionFactory> factory = |
| clang::tooling::newFrontendActionFactory(&match_finder); |
| int result = tool.run(factory.get()); |