Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Unified Diff: tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp

Issue 2256913002: Handling of DependentScopeDeclRefExpr and CXXDependentScopeMemberExpr nodes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blink-style-new-clang
Patch Set: Added a regression test that shows the necessity of IsCallee function. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..547f85e31b80f529fff15ad1301cc8e61eb92de7 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,34 @@ AST_MATCHER_P(clang::CXXMethodDecl,
return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder);
}
+// Matches |x.m| CXXDependentScopeMemberExpr if InnerMatcher matches |x|.
+AST_MATCHER_P(clang::CXXDependentScopeMemberExpr,
+ hasBaseExprMissingOrMatching,
+ clang::ast_matchers::internal::Matcher<clang::Expr>,
+ InnerMatcher) {
+ clang::Expr* base_expr = Node.isImplicitAccess() ? nullptr : Node.getBase();
+ return !base_expr || InnerMatcher.matches(*base_expr, Finder, Builder);
dcheng 2016/11/30 05:55:52 What's an implicit access look like? Why is it OK
Łukasz Anforowicz 2016/11/30 23:26:53 1. You are right that we should not return a match
dcheng 2016/12/01 07:15:06 I see. I think the usual preference is to have sma
Łukasz Anforowicz 2016/12/01 18:26:56 Acknowledged.
+}
+
+// Matches |T::m| CXXDependentScopeMemberExpr if InnerMatcher matches |T|.
+AST_MATCHER_P(
+ clang::CXXDependentScopeMemberExpr,
+ hasQualifierMissingOrMatching,
+ clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>,
+ InnerMatcher) {
+ clang::NestedNameSpecifier* qual = Node.getQualifier();
+ return !qual || InnerMatcher.matches(*qual, Finder, Builder);
dcheng 2016/11/30 05:55:52 Similar question here: why is it OK to return a ma
Łukasz Anforowicz 2016/11/30 23:26:53 See above.
+}
+
+// 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 +567,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 +731,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
+ // 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:
@@ -691,12 +774,26 @@ class UnresolvedRewriterBase : public RewriterBase<TargetNode> {
void run(const MatchFinder::MatchResult& result) override {
const TargetNode& expr = Base::GetTargetNode(result);
- llvm::StringRef old_name = GetUnresolvedName(expr).getAsString();
- std::string new_name;
- if (GuessNameForUnresolvedDependentNode(expr, *result.Context, old_name,
- new_name)) {
- Base::AddReplacement(result, old_name, std::move(new_name));
+
+ clang::DeclarationName unresolved_name = GetUnresolvedName(expr);
+ switch (unresolved_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;
+ default:
+ break;
}
+
+ std::string old_name = unresolved_name.getAsString();
+ std::string new_name = GuessNameForUnresolvedDependentNode(
+ expr, *result.Context, old_name);
+ if (!new_name.empty())
+ Base::AddReplacement(result, old_name, std::move(new_name));
}
private:
@@ -706,25 +803,25 @@ 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.
- bool GuessNameForUnresolvedDependentNode(const TargetNode& node,
+ //
+ // The guessed new name is returned (or an empty string if no name was
+ // guessed).
+ std::string GuessNameForUnresolvedDependentNode(const TargetNode& node,
dcheng 2016/11/30 05:55:52 Can we keep this consistent with GetNameForDecl()?
Łukasz Anforowicz 2016/11/30 23:26:53 Done (I think). There is some duplication for cal
dcheng 2016/12/01 07:15:06 I think I'm OK with passing old_name in; just havi
Łukasz Anforowicz 2016/12/01 18:26:57 Done.
clang::ASTContext& context,
- llvm::StringRef old_name,
- std::string& new_name) {
+ llvm::StringRef old_name) {
// |m_fieldName| -> |field_name_|.
if (old_name.startswith(kBlinkFieldPrefix)) {
- std::string field_name = old_name.str().substr(strlen(kBlinkFieldPrefix));
- if (field_name.find('_') == std::string::npos) {
- new_name = CamelCaseToUnderscoreCase(field_name) + "_";
- return true;
- }
+ std::string field_name = old_name.substr(strlen(kBlinkFieldPrefix));
+ if (field_name.find('_') == std::string::npos)
+ return CamelCaseToUnderscoreCase(field_name) + "_";
}
// |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;
+ std::string new_name = old_name;
new_name[0] = clang::toUppercase(new_name[0]);
- return true;
+ return new_name;
}
// In the future we can consider more heuristics:
@@ -732,7 +829,7 @@ class UnresolvedRewriterBase : public RewriterBase<TargetNode> {
// - "ALL_CAPS"
// - |T::myStaticField| -> |T::kMyStaticField|
// (but have to be careful not to rename |value| in WTF/TypeTraits.h?)
- return false;
+ return std::string();
}
};
@@ -742,6 +839,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 +1171,65 @@ 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(allOf(
+ hasBaseExprMissingOrMatching(hasType(blink_qual_type_matcher)),
+ hasQualifierMissingOrMatching(
+ specifiesType(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());
« no previous file with comments | « no previous file | tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698