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

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

Issue 1557243002: Update rewrite_to_chrome_style tool to also rename methods. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Group more logically Created 4 years, 11 months 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
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 42792382264884cb3775ab8ae16f3da27f46769b..fc710dd73fa841102110487159451e65cc6ebfc6 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -5,16 +5,18 @@
// Changes Blink-style names to Chrome-style names. Currently transforms:
// fields:
// int m_operationCount => int operation_count_
-// variables:
+// variables (including parameters):
// int mySuperVariable => int my_super_variable
// constants:
// const int maxThings => const int kMaxThings
danakj 2016/01/06 22:09:40 there are at least some constants named MaxThings.
dcheng 2016/01/08 01:41:11 It should (the heuristics for using kConstantStyle
-// free functions:
+// free functions and methods:
// void doThisThenThat() => void DoThisAndThat()
+#include <assert.h>
#include <algorithm>
#include <memory>
#include <string>
+#include <unordered_set>
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -38,12 +40,14 @@ using llvm::StringRef;
namespace {
+AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) {
+ return Node.isOverloadedOperator();
+}
+
constexpr char kBlinkFieldPrefix[] = "m_";
constexpr char kBlinkStaticMemberPrefix[] = "s_";
-bool GetNameForDecl(const clang::FunctionDecl& decl,
- clang::ASTContext* context,
- std::string& name) {
+bool GetNameForDecl(const clang::FunctionDecl& decl, std::string& name) {
name = decl.getNameAsString();
name[0] = clang::toUppercase(name[0]);
return true;
@@ -83,9 +87,7 @@ std::string CamelCaseToUnderscoreCase(StringRef input) {
return output;
}
-bool GetNameForDecl(const clang::FieldDecl& decl,
- clang::ASTContext* context,
- std::string& name) {
+bool GetNameForDecl(const clang::FieldDecl& decl, std::string& name) {
StringRef original_name = decl.getName();
// Blink style field names are prefixed with `m_`. If this prefix isn't
// present, assume it's already been converted to Google style.
@@ -137,9 +139,7 @@ bool IsProbablyConst(const clang::VarDecl& decl) {
clang::isa<clang::UserDefinedLiteral>(initializer);
}
-bool GetNameForDecl(const clang::VarDecl& decl,
- clang::ASTContext* context,
- std::string& name) {
+bool GetNameForDecl(const clang::VarDecl& decl, std::string& name) {
StringRef original_name = decl.getName();
// Nothing to do for unnamed parameters.
@@ -173,71 +173,165 @@ bool GetNameForDecl(const clang::VarDecl& decl,
return true;
}
-template <typename DeclNodeType, typename TargetTraits>
-class RewriterCallbackBase : public MatchFinder::MatchCallback {
- public:
- explicit RewriterCallbackBase(Replacements* replacements)
- : replacements_(replacements) {}
- virtual void run(const MatchFinder::MatchResult& result) override {
- std::string name;
- if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNodeType>("decl"),
- result.Context, name))
- return;
- replacements_->emplace(
- *result.SourceManager,
- TargetTraits::GetRange(
- *result.Nodes.getNodeAs<typename TargetTraits::NodeType>(
- TargetTraits::kName)),
- name);
- }
+template <typename Type>
+struct TargetNodeTraits;
- private:
- Replacements* const replacements_;
-};
-
-struct DeclTargetTraits {
- using NodeType = clang::NamedDecl;
+template <>
+struct TargetNodeTraits<clang::NamedDecl> {
static constexpr char kName[] = "decl";
- static clang::CharSourceRange GetRange(const NodeType& decl) {
+ static clang::CharSourceRange GetRange(const clang::NamedDecl& decl) {
return clang::CharSourceRange::getTokenRange(decl.getLocation());
}
};
-constexpr char DeclTargetTraits::kName[];
+constexpr char TargetNodeTraits<clang::NamedDecl>::kName[];
-struct ExprTargetTraits {
- using NodeType = clang::Expr;
+template <>
+struct TargetNodeTraits<clang::CallExpr> {
static constexpr char kName[] = "expr";
- static clang::CharSourceRange GetRange(const NodeType& expr) {
+ static clang::CharSourceRange GetRange(const clang::CallExpr& expr) {
return clang::CharSourceRange::getTokenRange(expr.getExprLoc());
}
};
-constexpr char ExprTargetTraits::kName[];
+constexpr char TargetNodeTraits<clang::CallExpr>::kName[];
+
+template <>
+struct TargetNodeTraits<clang::MemberExpr> {
+ static constexpr char kName[] = "expr";
+ static clang::CharSourceRange GetRange(const clang::MemberExpr& expr) {
+ return clang::CharSourceRange::getTokenRange(expr.getMemberLoc());
+ }
+};
+constexpr char TargetNodeTraits<clang::MemberExpr>::kName[];
-struct InitializerTargetTraits {
- using NodeType = clang::CXXCtorInitializer;
+template <>
+struct TargetNodeTraits<clang::DeclRefExpr> {
+ static constexpr char kName[] = "expr";
+ static clang::CharSourceRange GetRange(const clang::DeclRefExpr& expr) {
+ return clang::CharSourceRange::getTokenRange(expr.getLocation());
danakj 2016/01/06 22:09:40 consider a comment on each of these why you chose
dcheng 2016/01/08 01:41:11 I'm not sure how helpful a comment would be. It's
+ }
+};
+constexpr char TargetNodeTraits<clang::DeclRefExpr>::kName[];
+
+template <>
+struct TargetNodeTraits<clang::CXXCtorInitializer> {
static constexpr char kName[] = "initializer";
- static clang::CharSourceRange GetRange(const NodeType& init) {
+ static clang::CharSourceRange GetRange(
+ const clang::CXXCtorInitializer& init) {
return clang::CharSourceRange::getTokenRange(init.getSourceLocation());
}
};
-constexpr char InitializerTargetTraits::kName[];
+constexpr char TargetNodeTraits<clang::CXXCtorInitializer>::kName[];
+
+template <typename DeclNode, typename TargetNode>
+class RewriterBase : public MatchFinder::MatchCallback {
+ public:
+ explicit RewriterBase(Replacements* replacements)
+ : replacements_(replacements) {}
-using FunctionDeclRewriterCallback =
- RewriterCallbackBase<clang::FunctionDecl, DeclTargetTraits>;
-using FieldDeclRewriterCallback =
- RewriterCallbackBase<clang::FieldDecl, DeclTargetTraits>;
-using VarDeclRewriterCallback =
- RewriterCallbackBase<clang::VarDecl, DeclTargetTraits>;
+ void run(const MatchFinder::MatchResult& result) override {
+ std::string name;
+ if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNode>("decl"), name))
+ return;
+ replacements_->emplace(*result.SourceManager,
+ TargetNodeTraits<TargetNode>::GetRange(
+ *result.Nodes.getNodeAs<TargetNode>(
+ TargetNodeTraits<TargetNode>::kName)),
+ name);
+ }
-using CallRewriterCallback =
- RewriterCallbackBase<clang::FunctionDecl, ExprTargetTraits>;
-using MemberRewriterCallback =
- RewriterCallbackBase<clang::FieldDecl, ExprTargetTraits>;
-using DeclRefRewriterCallback =
- RewriterCallbackBase<clang::VarDecl, ExprTargetTraits>;
+ private:
+ Replacements* const replacements_;
+};
-using ConstructorInitializerRewriterCallback =
- RewriterCallbackBase<clang::FieldDecl, InitializerTargetTraits>;
+using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>;
+using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>;
+using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>;
+using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>;
+using ConstructorInitializerRewriter =
+ RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>;
+
+// Helpers for rewriting functions. The tool needs to detect overrides of Blink
+// methods, and uses two matchers to help accomplish this goal:
+// - The first matcher matches all method declarations in Blink. When the
+// callback rewrites the declaration, it also stores a pointer to the
+// canonical declaration, to record it as a Blink method.
+// - The second matcher matches all method declarations that are overrides. When
+// the callback processes the match, it checks if its overriding a method that
+// was marked as a Blink method. If so, it rewrites the declaration.
+// - Because an override is determined based on inclusion in the set of Blink
+// methods, the overridden methods matcher does not need to filter out special
+// member functions: they get filtered out by virtue of the first matcher.
+//
+// This works because per the documentation on MatchFinder:
+// The order of matches is guaranteed to be equivalent to doing a pre-order
+// traversal on the AST, and applying the matchers in the order in which they
+// were added to the MatchFinder.
+//
+// Since classes cannot forward declare their base classes, it is guaranteed
+// that the base class methods will be seen before processing the overridden
+// methods.
+class FunctionDeclRewriter
+ : public RewriterBase<clang::FunctionDecl, clang::NamedDecl> {
+ public:
+ explicit FunctionDeclRewriter(Replacements* replacements)
+ : RewriterBase(replacements) {}
+
+ void run(const MatchFinder::MatchResult& result) override {
+ if (const clang::CXXMethodDecl* method_decl =
+ result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl")) {
+ // TODO(dcheng): Does this need to check for the override attribute, or is
+ // this good enough?
+ if (method_decl->size_overridden_methods() > 0) {
+ if (!IsBlinkOverride(method_decl))
+ return;
+ } else {
+ blink_methods_.emplace(method_decl->getCanonicalDecl());
+ }
+ }
+
+ RewriterBase::run(result);
+ }
+
+ bool IsBlinkOverride(const clang::CXXMethodDecl* decl) const {
+ assert(decl->size_overridden_methods() > 0);
+ for (auto it = decl->begin_overridden_methods();
+ it != decl->end_overridden_methods(); ++it) {
+ if (blink_methods_.find((*it)->getCanonicalDecl()) !=
+ blink_methods_.end())
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ std::unordered_set<const clang::CXXMethodDecl*> blink_methods_;
+};
+
+template <typename BaseRewriter>
+class FilteringFunctionRewriter : public BaseRewriter {
+ public:
+ FilteringFunctionRewriter(const FunctionDeclRewriter& decl_rewriter,
+ Replacements* replacements)
+ : BaseRewriter(replacements), decl_rewriter_(decl_rewriter) {}
+
+ void run(const MatchFinder::MatchResult& result) override {
+ if (const clang::CXXMethodDecl* method_decl =
+ result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl")) {
+ if (method_decl->size_overridden_methods() > 0 &&
+ !decl_rewriter_.IsBlinkOverride(method_decl))
+ return;
+ }
+ BaseRewriter::run(result);
+ }
+
+ private:
+ const FunctionDeclRewriter& decl_rewriter_;
+};
+
+using CallRewriter = FilteringFunctionRewriter<
+ RewriterBase<clang::FunctionDecl, clang::CallExpr>>;
+using FunctionDeclRefRewriter = FilteringFunctionRewriter<
+ RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>>;
} // namespace
@@ -260,50 +354,77 @@ int main(int argc, const char* argv[]) {
auto in_blink_namespace =
decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF")))));
- // Declaration handling (e.g. function definitions and variable definitions):
-
- // Note: for now, only rewrite standalone functions until the question of JS
- // binding integration for class methods is resolved.
- // TODO(dcheng): Since classes in public/ aren't directly web-exposed, just go
- // ahead and rewrite those.
- auto function_decl_matcher =
- id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace));
-
+ // Declarations of fields and variables:
auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace));
auto var_decl_matcher = id("decl", varDecl(in_blink_namespace));
- FunctionDeclRewriterCallback function_decl_rewriter(&replacements);
- match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter);
- FieldDeclRewriterCallback field_decl_rewriter(&replacements);
+ FieldDeclRewriter field_decl_rewriter(&replacements);
match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter);
- VarDeclRewriterCallback var_decl_rewriter(&replacements);
+
+ VarDeclRewriter var_decl_rewriter(&replacements);
match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter);
- // Expression handling (e.g. calling a Blink function or referencing a
- // variable defined in Blink):
- auto call_matcher = id("expr", callExpr(callee(function_decl_matcher)));
+ // References to declared fields and variables:
auto member_matcher = id("expr", memberExpr(member(field_decl_matcher)));
auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher)));
- CallRewriterCallback call_rewriter(&replacements);
- match_finder.addMatcher(call_matcher, &call_rewriter);
- MemberRewriterCallback member_rewriter(&replacements);
+ MemberRewriter member_rewriter(&replacements);
match_finder.addMatcher(member_matcher, &member_rewriter);
- DeclRefRewriterCallback decl_ref_rewriter(&replacements);
+
+ DeclRefRewriter decl_ref_rewriter(&replacements);
match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter);
- // Function reference handling (e.g. getting a pointer to a function without
- // calling it):
+ // The AST matchers don't provide a good way to match against an override from
+ // a given class. Instead, use two matchers: one that matches the declarations
+ // (in Blink) and another which matches all overrides and performs some
+ // filtering.
+ auto function_decl_matcher =
+ id("decl",
+ functionDecl(unless(anyOf(cxxMethodDecl(isOverride()),
+ // Overloaded operators have special names
+ // and should never be renamed.
+ isOverloadedOperator(),
+ // Similarly, constructors and destructors
+ // should not be considered for renaming.
+ cxxConstructorDecl(), cxxDestructorDecl())),
+ in_blink_namespace));
+ // Note that the matcher for overridden methods doesn't need to filter for
+ // special member functions: see implementation of FunctionDeclRewriter for
+ // the explanation.
+ auto overridden_method_decl_matcher = id("decl", cxxMethodDecl(isOverride()));
+ FunctionDeclRewriter function_decl_rewriter(&replacements);
+ match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter);
+ match_finder.addMatcher(overridden_method_decl_matcher,
+ &function_decl_rewriter);
+
+ // Call handling:
+ auto call_matcher = id("expr", callExpr(callee(function_decl_matcher)));
+ auto overridden_call_matcher =
+ id("expr", callExpr(callee(overridden_method_decl_matcher)));
+
+ CallRewriter call_rewriter(function_decl_rewriter, &replacements);
+ match_finder.addMatcher(call_matcher, &call_rewriter);
+ match_finder.addMatcher(overridden_call_matcher, &call_rewriter);
+
+ // Function reference handling (e.g. getting a pointer to a function):
auto function_ref_matcher =
id("expr", declRefExpr(to(function_decl_matcher)));
- match_finder.addMatcher(function_ref_matcher, &call_rewriter);
+ // TODO(dcheng): apparently this bit of code isn't exercised in tests.
+ auto overridden_method_ref_matcher =
+ id("expr", declRefExpr(to(overridden_method_decl_matcher)));
+
+ FunctionDeclRefRewriter function_decl_ref_rewriter(function_decl_rewriter,
+ &replacements);
+ match_finder.addMatcher(function_ref_matcher, &function_decl_ref_rewriter);
+ match_finder.addMatcher(overridden_method_ref_matcher,
+ &function_decl_ref_rewriter);
// Initializer handling:
auto constructor_initializer_matcher =
cxxConstructorDecl(forEachConstructorInitializer(
id("initializer", cxxCtorInitializer(forField(field_decl_matcher)))));
- ConstructorInitializerRewriterCallback constructor_initializer_rewriter(
+ ConstructorInitializerRewriter constructor_initializer_rewriter(
&replacements);
match_finder.addMatcher(constructor_initializer_matcher,
&constructor_initializer_rewriter);

Powered by Google App Engine
This is Rietveld 408576698