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 |