Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Changes Blink-style names to Chrome-style names. Currently transforms: | 5 // Changes Blink-style names to Chrome-style names. Currently transforms: |
| 6 // fields: | 6 // fields: |
| 7 // int m_operationCount => int operation_count_ | 7 // int m_operationCount => int operation_count_ |
| 8 // variables: | 8 // variables (including parameters): |
| 9 // int mySuperVariable => int my_super_variable | 9 // int mySuperVariable => int my_super_variable |
| 10 // constants: | 10 // constants: |
| 11 // const int maxThings => const int kMaxThings | 11 // 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
| |
| 12 // free functions: | 12 // free functions and methods: |
| 13 // void doThisThenThat() => void DoThisAndThat() | 13 // void doThisThenThat() => void DoThisAndThat() |
| 14 | 14 |
| 15 #include <assert.h> | |
| 15 #include <algorithm> | 16 #include <algorithm> |
| 16 #include <memory> | 17 #include <memory> |
| 17 #include <string> | 18 #include <string> |
| 19 #include <unordered_set> | |
| 18 | 20 |
| 19 #include "clang/AST/ASTContext.h" | 21 #include "clang/AST/ASTContext.h" |
| 20 #include "clang/ASTMatchers/ASTMatchFinder.h" | 22 #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 21 #include "clang/ASTMatchers/ASTMatchers.h" | 23 #include "clang/ASTMatchers/ASTMatchers.h" |
| 22 #include "clang/ASTMatchers/ASTMatchersMacros.h" | 24 #include "clang/ASTMatchers/ASTMatchersMacros.h" |
| 23 #include "clang/Basic/CharInfo.h" | 25 #include "clang/Basic/CharInfo.h" |
| 24 #include "clang/Basic/SourceManager.h" | 26 #include "clang/Basic/SourceManager.h" |
| 25 #include "clang/Frontend/FrontendActions.h" | 27 #include "clang/Frontend/FrontendActions.h" |
| 26 #include "clang/Lex/Lexer.h" | 28 #include "clang/Lex/Lexer.h" |
| 27 #include "clang/Tooling/CommonOptionsParser.h" | 29 #include "clang/Tooling/CommonOptionsParser.h" |
| 28 #include "clang/Tooling/Refactoring.h" | 30 #include "clang/Tooling/Refactoring.h" |
| 29 #include "clang/Tooling/Tooling.h" | 31 #include "clang/Tooling/Tooling.h" |
| 30 #include "llvm/Support/CommandLine.h" | 32 #include "llvm/Support/CommandLine.h" |
| 31 #include "llvm/Support/TargetSelect.h" | 33 #include "llvm/Support/TargetSelect.h" |
| 32 | 34 |
| 33 using namespace clang::ast_matchers; | 35 using namespace clang::ast_matchers; |
| 34 using clang::tooling::CommonOptionsParser; | 36 using clang::tooling::CommonOptionsParser; |
| 35 using clang::tooling::Replacement; | 37 using clang::tooling::Replacement; |
| 36 using clang::tooling::Replacements; | 38 using clang::tooling::Replacements; |
| 37 using llvm::StringRef; | 39 using llvm::StringRef; |
| 38 | 40 |
| 39 namespace { | 41 namespace { |
| 40 | 42 |
| 43 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { | |
| 44 return Node.isOverloadedOperator(); | |
| 45 } | |
| 46 | |
| 41 constexpr char kBlinkFieldPrefix[] = "m_"; | 47 constexpr char kBlinkFieldPrefix[] = "m_"; |
| 42 constexpr char kBlinkStaticMemberPrefix[] = "s_"; | 48 constexpr char kBlinkStaticMemberPrefix[] = "s_"; |
| 43 | 49 |
| 44 bool GetNameForDecl(const clang::FunctionDecl& decl, | 50 bool GetNameForDecl(const clang::FunctionDecl& decl, std::string& name) { |
| 45 clang::ASTContext* context, | |
| 46 std::string& name) { | |
| 47 name = decl.getNameAsString(); | 51 name = decl.getNameAsString(); |
| 48 name[0] = clang::toUppercase(name[0]); | 52 name[0] = clang::toUppercase(name[0]); |
| 49 return true; | 53 return true; |
| 50 } | 54 } |
| 51 | 55 |
| 52 // Helper to convert from a camelCaseName to camel_case_name. It uses some | 56 // Helper to convert from a camelCaseName to camel_case_name. It uses some |
| 53 // heuristics to try to handle acronyms in camel case names correctly. | 57 // heuristics to try to handle acronyms in camel case names correctly. |
| 54 std::string CamelCaseToUnderscoreCase(StringRef input) { | 58 std::string CamelCaseToUnderscoreCase(StringRef input) { |
| 55 std::string output; | 59 std::string output; |
| 56 bool needs_underscore = false; | 60 bool needs_underscore = false; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 76 // needs a '_' in 'dL'. | 80 // needs a '_' in 'dL'. |
| 77 if (i != input.bytes_end() - 1 && was_lowercase && is_uppercase) | 81 if (i != input.bytes_end() - 1 && was_lowercase && is_uppercase) |
| 78 needs_underscore = true; | 82 needs_underscore = true; |
| 79 was_lowercase = is_lowercase; | 83 was_lowercase = is_lowercase; |
| 80 was_uppercase = is_uppercase; | 84 was_uppercase = is_uppercase; |
| 81 } | 85 } |
| 82 std::reverse(output.begin(), output.end()); | 86 std::reverse(output.begin(), output.end()); |
| 83 return output; | 87 return output; |
| 84 } | 88 } |
| 85 | 89 |
| 86 bool GetNameForDecl(const clang::FieldDecl& decl, | 90 bool GetNameForDecl(const clang::FieldDecl& decl, std::string& name) { |
| 87 clang::ASTContext* context, | |
| 88 std::string& name) { | |
| 89 StringRef original_name = decl.getName(); | 91 StringRef original_name = decl.getName(); |
| 90 // Blink style field names are prefixed with `m_`. If this prefix isn't | 92 // Blink style field names are prefixed with `m_`. If this prefix isn't |
| 91 // present, assume it's already been converted to Google style. | 93 // present, assume it's already been converted to Google style. |
| 92 if (original_name.size() < strlen(kBlinkFieldPrefix) || | 94 if (original_name.size() < strlen(kBlinkFieldPrefix) || |
| 93 !original_name.startswith(kBlinkFieldPrefix)) | 95 !original_name.startswith(kBlinkFieldPrefix)) |
| 94 return false; | 96 return false; |
| 95 name = CamelCaseToUnderscoreCase( | 97 name = CamelCaseToUnderscoreCase( |
| 96 original_name.substr(strlen(kBlinkFieldPrefix))); | 98 original_name.substr(strlen(kBlinkFieldPrefix))); |
| 97 // The few examples I could find used struct-style naming with no `_` suffix | 99 // The few examples I could find used struct-style naming with no `_` suffix |
| 98 // for unions. | 100 // for unions. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 return clang::isa<clang::CharacterLiteral>(initializer) || | 132 return clang::isa<clang::CharacterLiteral>(initializer) || |
| 131 clang::isa<clang::CompoundLiteralExpr>(initializer) || | 133 clang::isa<clang::CompoundLiteralExpr>(initializer) || |
| 132 clang::isa<clang::CXXBoolLiteralExpr>(initializer) || | 134 clang::isa<clang::CXXBoolLiteralExpr>(initializer) || |
| 133 clang::isa<clang::CXXNullPtrLiteralExpr>(initializer) || | 135 clang::isa<clang::CXXNullPtrLiteralExpr>(initializer) || |
| 134 clang::isa<clang::FloatingLiteral>(initializer) || | 136 clang::isa<clang::FloatingLiteral>(initializer) || |
| 135 clang::isa<clang::IntegerLiteral>(initializer) || | 137 clang::isa<clang::IntegerLiteral>(initializer) || |
| 136 clang::isa<clang::StringLiteral>(initializer) || | 138 clang::isa<clang::StringLiteral>(initializer) || |
| 137 clang::isa<clang::UserDefinedLiteral>(initializer); | 139 clang::isa<clang::UserDefinedLiteral>(initializer); |
| 138 } | 140 } |
| 139 | 141 |
| 140 bool GetNameForDecl(const clang::VarDecl& decl, | 142 bool GetNameForDecl(const clang::VarDecl& decl, std::string& name) { |
| 141 clang::ASTContext* context, | |
| 142 std::string& name) { | |
| 143 StringRef original_name = decl.getName(); | 143 StringRef original_name = decl.getName(); |
| 144 | 144 |
| 145 // Nothing to do for unnamed parameters. | 145 // Nothing to do for unnamed parameters. |
| 146 if (clang::isa<clang::ParmVarDecl>(decl) && original_name.empty()) | 146 if (clang::isa<clang::ParmVarDecl>(decl) && original_name.empty()) |
| 147 return false; | 147 return false; |
| 148 | 148 |
| 149 // static class members match against VarDecls. Blink style dictates that | 149 // static class members match against VarDecls. Blink style dictates that |
| 150 // these should be prefixed with `s_`, so strip that off. Also check for `m_` | 150 // these should be prefixed with `s_`, so strip that off. Also check for `m_` |
| 151 // and strip that off too, for code that accidentally uses the wrong prefix. | 151 // and strip that off too, for code that accidentally uses the wrong prefix. |
| 152 if (original_name.startswith(kBlinkStaticMemberPrefix)) | 152 if (original_name.startswith(kBlinkStaticMemberPrefix)) |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 166 name = CamelCaseToUnderscoreCase(original_name); | 166 name = CamelCaseToUnderscoreCase(original_name); |
| 167 } | 167 } |
| 168 | 168 |
| 169 if (decl.isStaticDataMember()) { | 169 if (decl.isStaticDataMember()) { |
| 170 name += '_'; | 170 name += '_'; |
| 171 } | 171 } |
| 172 | 172 |
| 173 return true; | 173 return true; |
| 174 } | 174 } |
| 175 | 175 |
| 176 template <typename DeclNodeType, typename TargetTraits> | 176 template <typename Type> |
| 177 class RewriterCallbackBase : public MatchFinder::MatchCallback { | 177 struct TargetNodeTraits; |
| 178 | |
| 179 template <> | |
| 180 struct TargetNodeTraits<clang::NamedDecl> { | |
| 181 static constexpr char kName[] = "decl"; | |
| 182 static clang::CharSourceRange GetRange(const clang::NamedDecl& decl) { | |
| 183 return clang::CharSourceRange::getTokenRange(decl.getLocation()); | |
| 184 } | |
| 185 }; | |
| 186 constexpr char TargetNodeTraits<clang::NamedDecl>::kName[]; | |
| 187 | |
| 188 template <> | |
| 189 struct TargetNodeTraits<clang::CallExpr> { | |
| 190 static constexpr char kName[] = "expr"; | |
| 191 static clang::CharSourceRange GetRange(const clang::CallExpr& expr) { | |
| 192 return clang::CharSourceRange::getTokenRange(expr.getExprLoc()); | |
| 193 } | |
| 194 }; | |
| 195 constexpr char TargetNodeTraits<clang::CallExpr>::kName[]; | |
| 196 | |
| 197 template <> | |
| 198 struct TargetNodeTraits<clang::MemberExpr> { | |
| 199 static constexpr char kName[] = "expr"; | |
| 200 static clang::CharSourceRange GetRange(const clang::MemberExpr& expr) { | |
| 201 return clang::CharSourceRange::getTokenRange(expr.getMemberLoc()); | |
| 202 } | |
| 203 }; | |
| 204 constexpr char TargetNodeTraits<clang::MemberExpr>::kName[]; | |
| 205 | |
| 206 template <> | |
| 207 struct TargetNodeTraits<clang::DeclRefExpr> { | |
| 208 static constexpr char kName[] = "expr"; | |
| 209 static clang::CharSourceRange GetRange(const clang::DeclRefExpr& expr) { | |
| 210 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
| |
| 211 } | |
| 212 }; | |
| 213 constexpr char TargetNodeTraits<clang::DeclRefExpr>::kName[]; | |
| 214 | |
| 215 template <> | |
| 216 struct TargetNodeTraits<clang::CXXCtorInitializer> { | |
| 217 static constexpr char kName[] = "initializer"; | |
| 218 static clang::CharSourceRange GetRange( | |
| 219 const clang::CXXCtorInitializer& init) { | |
| 220 return clang::CharSourceRange::getTokenRange(init.getSourceLocation()); | |
| 221 } | |
| 222 }; | |
| 223 constexpr char TargetNodeTraits<clang::CXXCtorInitializer>::kName[]; | |
| 224 | |
| 225 template <typename DeclNode, typename TargetNode> | |
| 226 class RewriterBase : public MatchFinder::MatchCallback { | |
| 178 public: | 227 public: |
| 179 explicit RewriterCallbackBase(Replacements* replacements) | 228 explicit RewriterBase(Replacements* replacements) |
| 180 : replacements_(replacements) {} | 229 : replacements_(replacements) {} |
| 181 virtual void run(const MatchFinder::MatchResult& result) override { | 230 |
| 231 void run(const MatchFinder::MatchResult& result) override { | |
| 182 std::string name; | 232 std::string name; |
| 183 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNodeType>("decl"), | 233 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNode>("decl"), name)) |
| 184 result.Context, name)) | |
| 185 return; | 234 return; |
| 186 replacements_->emplace( | 235 replacements_->emplace(*result.SourceManager, |
| 187 *result.SourceManager, | 236 TargetNodeTraits<TargetNode>::GetRange( |
| 188 TargetTraits::GetRange( | 237 *result.Nodes.getNodeAs<TargetNode>( |
| 189 *result.Nodes.getNodeAs<typename TargetTraits::NodeType>( | 238 TargetNodeTraits<TargetNode>::kName)), |
| 190 TargetTraits::kName)), | 239 name); |
| 191 name); | |
| 192 } | 240 } |
| 193 | 241 |
| 194 private: | 242 private: |
| 195 Replacements* const replacements_; | 243 Replacements* const replacements_; |
| 196 }; | 244 }; |
| 197 | 245 |
| 198 struct DeclTargetTraits { | 246 using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>; |
| 199 using NodeType = clang::NamedDecl; | 247 using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>; |
| 200 static constexpr char kName[] = "decl"; | 248 using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>; |
| 201 static clang::CharSourceRange GetRange(const NodeType& decl) { | 249 using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>; |
| 202 return clang::CharSourceRange::getTokenRange(decl.getLocation()); | 250 using ConstructorInitializerRewriter = |
| 251 RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>; | |
| 252 | |
| 253 // Helpers for rewriting functions. The tool needs to detect overrides of Blink | |
| 254 // methods, and uses two matchers to help accomplish this goal: | |
| 255 // - The first matcher matches all method declarations in Blink. When the | |
| 256 // callback rewrites the declaration, it also stores a pointer to the | |
| 257 // canonical declaration, to record it as a Blink method. | |
| 258 // - The second matcher matches all method declarations that are overrides. When | |
| 259 // the callback processes the match, it checks if its overriding a method that | |
| 260 // was marked as a Blink method. If so, it rewrites the declaration. | |
| 261 // - Because an override is determined based on inclusion in the set of Blink | |
| 262 // methods, the overridden methods matcher does not need to filter out special | |
| 263 // member functions: they get filtered out by virtue of the first matcher. | |
| 264 // | |
| 265 // This works because per the documentation on MatchFinder: | |
| 266 // The order of matches is guaranteed to be equivalent to doing a pre-order | |
| 267 // traversal on the AST, and applying the matchers in the order in which they | |
| 268 // were added to the MatchFinder. | |
| 269 // | |
| 270 // Since classes cannot forward declare their base classes, it is guaranteed | |
| 271 // that the base class methods will be seen before processing the overridden | |
| 272 // methods. | |
| 273 class FunctionDeclRewriter | |
| 274 : public RewriterBase<clang::FunctionDecl, clang::NamedDecl> { | |
| 275 public: | |
| 276 explicit FunctionDeclRewriter(Replacements* replacements) | |
| 277 : RewriterBase(replacements) {} | |
| 278 | |
| 279 void run(const MatchFinder::MatchResult& result) override { | |
| 280 if (const clang::CXXMethodDecl* method_decl = | |
| 281 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl")) { | |
| 282 // TODO(dcheng): Does this need to check for the override attribute, or is | |
| 283 // this good enough? | |
| 284 if (method_decl->size_overridden_methods() > 0) { | |
| 285 if (!IsBlinkOverride(method_decl)) | |
| 286 return; | |
| 287 } else { | |
| 288 blink_methods_.emplace(method_decl->getCanonicalDecl()); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 RewriterBase::run(result); | |
| 203 } | 293 } |
| 294 | |
| 295 bool IsBlinkOverride(const clang::CXXMethodDecl* decl) const { | |
| 296 assert(decl->size_overridden_methods() > 0); | |
| 297 for (auto it = decl->begin_overridden_methods(); | |
| 298 it != decl->end_overridden_methods(); ++it) { | |
| 299 if (blink_methods_.find((*it)->getCanonicalDecl()) != | |
| 300 blink_methods_.end()) | |
| 301 return true; | |
| 302 } | |
| 303 return false; | |
| 304 } | |
| 305 | |
| 306 private: | |
| 307 std::unordered_set<const clang::CXXMethodDecl*> blink_methods_; | |
| 204 }; | 308 }; |
| 205 constexpr char DeclTargetTraits::kName[]; | |
| 206 | 309 |
| 207 struct ExprTargetTraits { | 310 template <typename BaseRewriter> |
| 208 using NodeType = clang::Expr; | 311 class FilteringFunctionRewriter : public BaseRewriter { |
| 209 static constexpr char kName[] = "expr"; | 312 public: |
| 210 static clang::CharSourceRange GetRange(const NodeType& expr) { | 313 FilteringFunctionRewriter(const FunctionDeclRewriter& decl_rewriter, |
| 211 return clang::CharSourceRange::getTokenRange(expr.getExprLoc()); | 314 Replacements* replacements) |
| 315 : BaseRewriter(replacements), decl_rewriter_(decl_rewriter) {} | |
| 316 | |
| 317 void run(const MatchFinder::MatchResult& result) override { | |
| 318 if (const clang::CXXMethodDecl* method_decl = | |
| 319 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl")) { | |
| 320 if (method_decl->size_overridden_methods() > 0 && | |
| 321 !decl_rewriter_.IsBlinkOverride(method_decl)) | |
| 322 return; | |
| 323 } | |
| 324 BaseRewriter::run(result); | |
| 212 } | 325 } |
| 326 | |
| 327 private: | |
| 328 const FunctionDeclRewriter& decl_rewriter_; | |
| 213 }; | 329 }; |
| 214 constexpr char ExprTargetTraits::kName[]; | |
| 215 | 330 |
| 216 struct InitializerTargetTraits { | 331 using CallRewriter = FilteringFunctionRewriter< |
| 217 using NodeType = clang::CXXCtorInitializer; | 332 RewriterBase<clang::FunctionDecl, clang::CallExpr>>; |
| 218 static constexpr char kName[] = "initializer"; | 333 using FunctionDeclRefRewriter = FilteringFunctionRewriter< |
| 219 static clang::CharSourceRange GetRange(const NodeType& init) { | 334 RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>>; |
| 220 return clang::CharSourceRange::getTokenRange(init.getSourceLocation()); | |
| 221 } | |
| 222 }; | |
| 223 constexpr char InitializerTargetTraits::kName[]; | |
| 224 | |
| 225 using FunctionDeclRewriterCallback = | |
| 226 RewriterCallbackBase<clang::FunctionDecl, DeclTargetTraits>; | |
| 227 using FieldDeclRewriterCallback = | |
| 228 RewriterCallbackBase<clang::FieldDecl, DeclTargetTraits>; | |
| 229 using VarDeclRewriterCallback = | |
| 230 RewriterCallbackBase<clang::VarDecl, DeclTargetTraits>; | |
| 231 | |
| 232 using CallRewriterCallback = | |
| 233 RewriterCallbackBase<clang::FunctionDecl, ExprTargetTraits>; | |
| 234 using MemberRewriterCallback = | |
| 235 RewriterCallbackBase<clang::FieldDecl, ExprTargetTraits>; | |
| 236 using DeclRefRewriterCallback = | |
| 237 RewriterCallbackBase<clang::VarDecl, ExprTargetTraits>; | |
| 238 | |
| 239 using ConstructorInitializerRewriterCallback = | |
| 240 RewriterCallbackBase<clang::FieldDecl, InitializerTargetTraits>; | |
| 241 | 335 |
| 242 } // namespace | 336 } // namespace |
| 243 | 337 |
| 244 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 338 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
| 245 | 339 |
| 246 int main(int argc, const char* argv[]) { | 340 int main(int argc, const char* argv[]) { |
| 247 // TODO(dcheng): Clang tooling should do this itself. | 341 // TODO(dcheng): Clang tooling should do this itself. |
| 248 // http://llvm.org/bugs/show_bug.cgi?id=21627 | 342 // http://llvm.org/bugs/show_bug.cgi?id=21627 |
| 249 llvm::InitializeNativeTarget(); | 343 llvm::InitializeNativeTarget(); |
| 250 llvm::InitializeNativeTargetAsmParser(); | 344 llvm::InitializeNativeTargetAsmParser(); |
| 251 llvm::cl::OptionCategory category( | 345 llvm::cl::OptionCategory category( |
| 252 "rewrite_to_chrome_style: convert Blink style to Chrome style."); | 346 "rewrite_to_chrome_style: convert Blink style to Chrome style."); |
| 253 CommonOptionsParser options(argc, argv, category); | 347 CommonOptionsParser options(argc, argv, category); |
| 254 clang::tooling::ClangTool tool(options.getCompilations(), | 348 clang::tooling::ClangTool tool(options.getCompilations(), |
| 255 options.getSourcePathList()); | 349 options.getSourcePathList()); |
| 256 | 350 |
| 257 MatchFinder match_finder; | 351 MatchFinder match_finder; |
| 258 Replacements replacements; | 352 Replacements replacements; |
| 259 | 353 |
| 260 auto in_blink_namespace = | 354 auto in_blink_namespace = |
| 261 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); | 355 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); |
| 262 | 356 |
| 263 // Declaration handling (e.g. function definitions and variable definitions): | 357 // Declarations of fields and variables: |
| 264 | |
| 265 // Note: for now, only rewrite standalone functions until the question of JS | |
| 266 // binding integration for class methods is resolved. | |
| 267 // TODO(dcheng): Since classes in public/ aren't directly web-exposed, just go | |
| 268 // ahead and rewrite those. | |
| 269 auto function_decl_matcher = | |
| 270 id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace)); | |
| 271 | |
| 272 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); | 358 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); |
| 273 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); | 359 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); |
| 274 | 360 |
| 275 FunctionDeclRewriterCallback function_decl_rewriter(&replacements); | 361 FieldDeclRewriter field_decl_rewriter(&replacements); |
| 276 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); | |
| 277 FieldDeclRewriterCallback field_decl_rewriter(&replacements); | |
| 278 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); | 362 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); |
| 279 VarDeclRewriterCallback var_decl_rewriter(&replacements); | 363 |
| 364 VarDeclRewriter var_decl_rewriter(&replacements); | |
| 280 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); | 365 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); |
| 281 | 366 |
| 282 // Expression handling (e.g. calling a Blink function or referencing a | 367 // References to declared fields and variables: |
| 283 // variable defined in Blink): | |
| 284 auto call_matcher = id("expr", callExpr(callee(function_decl_matcher))); | |
| 285 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); | 368 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); |
| 286 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); | 369 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); |
| 287 | 370 |
| 288 CallRewriterCallback call_rewriter(&replacements); | 371 MemberRewriter member_rewriter(&replacements); |
| 289 match_finder.addMatcher(call_matcher, &call_rewriter); | |
| 290 MemberRewriterCallback member_rewriter(&replacements); | |
| 291 match_finder.addMatcher(member_matcher, &member_rewriter); | 372 match_finder.addMatcher(member_matcher, &member_rewriter); |
| 292 DeclRefRewriterCallback decl_ref_rewriter(&replacements); | 373 |
| 374 DeclRefRewriter decl_ref_rewriter(&replacements); | |
| 293 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); | 375 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); |
| 294 | 376 |
| 295 // Function reference handling (e.g. getting a pointer to a function without | 377 // The AST matchers don't provide a good way to match against an override from |
| 296 // calling it): | 378 // a given class. Instead, use two matchers: one that matches the declarations |
| 379 // (in Blink) and another which matches all overrides and performs some | |
| 380 // filtering. | |
| 381 auto function_decl_matcher = | |
| 382 id("decl", | |
| 383 functionDecl(unless(anyOf(cxxMethodDecl(isOverride()), | |
| 384 // Overloaded operators have special names | |
| 385 // and should never be renamed. | |
| 386 isOverloadedOperator(), | |
| 387 // Similarly, constructors and destructors | |
| 388 // should not be considered for renaming. | |
| 389 cxxConstructorDecl(), cxxDestructorDecl())), | |
| 390 in_blink_namespace)); | |
| 391 // Note that the matcher for overridden methods doesn't need to filter for | |
| 392 // special member functions: see implementation of FunctionDeclRewriter for | |
| 393 // the explanation. | |
| 394 auto overridden_method_decl_matcher = id("decl", cxxMethodDecl(isOverride())); | |
| 395 FunctionDeclRewriter function_decl_rewriter(&replacements); | |
| 396 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); | |
| 397 match_finder.addMatcher(overridden_method_decl_matcher, | |
| 398 &function_decl_rewriter); | |
| 399 | |
| 400 // Call handling: | |
| 401 auto call_matcher = id("expr", callExpr(callee(function_decl_matcher))); | |
| 402 auto overridden_call_matcher = | |
| 403 id("expr", callExpr(callee(overridden_method_decl_matcher))); | |
| 404 | |
| 405 CallRewriter call_rewriter(function_decl_rewriter, &replacements); | |
| 406 match_finder.addMatcher(call_matcher, &call_rewriter); | |
| 407 match_finder.addMatcher(overridden_call_matcher, &call_rewriter); | |
| 408 | |
| 409 // Function reference handling (e.g. getting a pointer to a function): | |
| 297 auto function_ref_matcher = | 410 auto function_ref_matcher = |
| 298 id("expr", declRefExpr(to(function_decl_matcher))); | 411 id("expr", declRefExpr(to(function_decl_matcher))); |
| 299 match_finder.addMatcher(function_ref_matcher, &call_rewriter); | 412 // TODO(dcheng): apparently this bit of code isn't exercised in tests. |
| 413 auto overridden_method_ref_matcher = | |
| 414 id("expr", declRefExpr(to(overridden_method_decl_matcher))); | |
| 415 | |
| 416 FunctionDeclRefRewriter function_decl_ref_rewriter(function_decl_rewriter, | |
| 417 &replacements); | |
| 418 match_finder.addMatcher(function_ref_matcher, &function_decl_ref_rewriter); | |
| 419 match_finder.addMatcher(overridden_method_ref_matcher, | |
| 420 &function_decl_ref_rewriter); | |
| 300 | 421 |
| 301 // Initializer handling: | 422 // Initializer handling: |
| 302 auto constructor_initializer_matcher = | 423 auto constructor_initializer_matcher = |
| 303 cxxConstructorDecl(forEachConstructorInitializer( | 424 cxxConstructorDecl(forEachConstructorInitializer( |
| 304 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); | 425 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); |
| 305 | 426 |
| 306 ConstructorInitializerRewriterCallback constructor_initializer_rewriter( | 427 ConstructorInitializerRewriter constructor_initializer_rewriter( |
| 307 &replacements); | 428 &replacements); |
| 308 match_finder.addMatcher(constructor_initializer_matcher, | 429 match_finder.addMatcher(constructor_initializer_matcher, |
| 309 &constructor_initializer_rewriter); | 430 &constructor_initializer_rewriter); |
| 310 | 431 |
| 311 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = | 432 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = |
| 312 clang::tooling::newFrontendActionFactory(&match_finder); | 433 clang::tooling::newFrontendActionFactory(&match_finder); |
| 313 int result = tool.run(factory.get()); | 434 int result = tool.run(factory.get()); |
| 314 if (result != 0) | 435 if (result != 0) |
| 315 return result; | 436 return result; |
| 316 | 437 |
| 317 // Serialization format is documented in tools/clang/scripts/run_tool.py | 438 // Serialization format is documented in tools/clang/scripts/run_tool.py |
| 318 llvm::outs() << "==== BEGIN EDITS ====\n"; | 439 llvm::outs() << "==== BEGIN EDITS ====\n"; |
| 319 for (const auto& r : replacements) { | 440 for (const auto& r : replacements) { |
| 320 std::string replacement_text = r.getReplacementText().str(); | 441 std::string replacement_text = r.getReplacementText().str(); |
| 321 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); | 442 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); |
| 322 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 443 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() |
| 323 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; | 444 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; |
| 324 } | 445 } |
| 325 llvm::outs() << "==== END EDITS ====\n"; | 446 llvm::outs() << "==== END EDITS ====\n"; |
| 326 | 447 |
| 327 return 0; | 448 return 0; |
| 328 } | 449 } |
| OLD | NEW |