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 |
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::MemberExpr> { | |
190 static constexpr char kName[] = "expr"; | |
191 static clang::CharSourceRange GetRange(const clang::MemberExpr& expr) { | |
192 return clang::CharSourceRange::getTokenRange(expr.getMemberLoc()); | |
193 } | |
194 }; | |
195 constexpr char TargetNodeTraits<clang::MemberExpr>::kName[]; | |
196 | |
197 template <> | |
198 struct TargetNodeTraits<clang::DeclRefExpr> { | |
199 static constexpr char kName[] = "expr"; | |
200 static clang::CharSourceRange GetRange(const clang::DeclRefExpr& expr) { | |
201 return clang::CharSourceRange::getTokenRange(expr.getLocation()); | |
202 } | |
203 }; | |
204 constexpr char TargetNodeTraits<clang::DeclRefExpr>::kName[]; | |
205 | |
206 template <> | |
207 struct TargetNodeTraits<clang::CXXCtorInitializer> { | |
208 static constexpr char kName[] = "initializer"; | |
209 static clang::CharSourceRange GetRange( | |
210 const clang::CXXCtorInitializer& init) { | |
211 return clang::CharSourceRange::getTokenRange(init.getSourceLocation()); | |
212 } | |
213 }; | |
214 constexpr char TargetNodeTraits<clang::CXXCtorInitializer>::kName[]; | |
215 | |
216 template <typename DeclNode, typename TargetNode> | |
217 class RewriterBase : public MatchFinder::MatchCallback { | |
178 public: | 218 public: |
179 explicit RewriterCallbackBase(Replacements* replacements) | 219 explicit RewriterBase(Replacements* replacements) |
180 : replacements_(replacements) {} | 220 : replacements_(replacements) {} |
181 virtual void run(const MatchFinder::MatchResult& result) override { | 221 |
222 void run(const MatchFinder::MatchResult& result) override { | |
182 std::string name; | 223 std::string name; |
183 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNodeType>("decl"), | 224 if (!GetNameForDecl(*result.Nodes.getNodeAs<DeclNode>("decl"), name)) |
184 result.Context, name)) | |
185 return; | 225 return; |
186 replacements_->emplace( | 226 replacements_->emplace(*result.SourceManager, |
187 *result.SourceManager, | 227 TargetNodeTraits<TargetNode>::GetRange( |
188 TargetTraits::GetRange( | 228 *result.Nodes.getNodeAs<TargetNode>( |
189 *result.Nodes.getNodeAs<typename TargetTraits::NodeType>( | 229 TargetNodeTraits<TargetNode>::kName)), |
190 TargetTraits::kName)), | 230 name); |
191 name); | |
192 } | 231 } |
193 | 232 |
194 private: | 233 private: |
195 Replacements* const replacements_; | 234 Replacements* const replacements_; |
196 }; | 235 }; |
197 | 236 |
198 struct DeclTargetTraits { | 237 using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>; |
199 using NodeType = clang::NamedDecl; | 238 using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>; |
200 static constexpr char kName[] = "decl"; | 239 using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>; |
201 static clang::CharSourceRange GetRange(const NodeType& decl) { | 240 using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>; |
202 return clang::CharSourceRange::getTokenRange(decl.getLocation()); | 241 using FunctionDeclRewriter = |
242 RewriterBase<clang::FunctionDecl, clang::NamedDecl>; | |
243 using FunctionRefRewriter = | |
244 RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>; | |
245 using ConstructorInitializerRewriter = | |
246 RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>; | |
247 | |
248 // Helpers for rewriting methods. The tool needs to detect overrides of Blink | |
249 // methods, and uses two matchers to help accomplish this goal: | |
250 // - The first matcher matches all method declarations in Blink. When the | |
251 // callback rewrites the declaration, it also stores a pointer to the | |
252 // canonical declaration, to record it as a Blink method. | |
253 // - The second matcher matches all method declarations that are overrides. When | |
254 // the callback processes the match, it checks if its overriding a method that | |
255 // was marked as a Blink method. If so, it rewrites the declaration. | |
256 // - Because an override is determined based on inclusion in the set of Blink | |
257 // methods, the overridden methods matcher does not need to filter out special | |
258 // member functions: they get filtered out by virtue of the first matcher. | |
259 // | |
260 // This works because per the documentation on MatchFinder: | |
261 // The order of matches is guaranteed to be equivalent to doing a pre-order | |
262 // traversal on the AST, and applying the matchers in the order in which they | |
263 // were added to the MatchFinder. | |
264 // | |
265 // Since classes cannot forward declare their base classes, it is guaranteed | |
266 // that the base class methods will be seen before processing the overridden | |
267 // methods. | |
268 class MethodDeclRewriter | |
269 : public RewriterBase<clang::CXXMethodDecl, clang::NamedDecl> { | |
270 public: | |
271 explicit MethodDeclRewriter(Replacements* replacements) | |
272 : RewriterBase(replacements) {} | |
273 | |
274 void run(const MatchFinder::MatchResult& result) override { | |
275 const clang::CXXMethodDecl* method_decl = | |
276 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl"); | |
277 // TODO(dcheng): Does this need to check for the override attribute, or is | |
278 // this good enough? | |
279 if (method_decl->size_overridden_methods() > 0) { | |
280 if (!IsBlinkOverride(method_decl)) | |
281 return; | |
282 } else { | |
283 blink_methods_.emplace(method_decl->getCanonicalDecl()); | |
284 } | |
285 | |
286 RewriterBase::run(result); | |
203 } | 287 } |
288 | |
289 bool IsBlinkOverride(const clang::CXXMethodDecl* decl) const { | |
290 assert(decl->size_overridden_methods() > 0); | |
291 for (auto it = decl->begin_overridden_methods(); | |
292 it != decl->end_overridden_methods(); ++it) { | |
293 if (blink_methods_.find((*it)->getCanonicalDecl()) != | |
294 blink_methods_.end()) | |
295 return true; | |
296 } | |
297 return false; | |
298 } | |
299 | |
300 private: | |
301 std::unordered_set<const clang::CXXMethodDecl*> blink_methods_; | |
204 }; | 302 }; |
205 constexpr char DeclTargetTraits::kName[]; | |
206 | 303 |
207 struct ExprTargetTraits { | 304 template <typename RewriterBase> |
danakj
2016/01/08 02:02:52
This name is conflicty with a real type. The old n
dcheng
2016/01/08 02:14:01
I thought Base might be too vague, but I'll admit
| |
208 using NodeType = clang::Expr; | 305 class FilteringMethodRewriter : public RewriterBase { |
209 static constexpr char kName[] = "expr"; | 306 public: |
210 static clang::CharSourceRange GetRange(const NodeType& expr) { | 307 FilteringMethodRewriter(const MethodDeclRewriter& decl_rewriter, |
211 return clang::CharSourceRange::getTokenRange(expr.getExprLoc()); | 308 Replacements* replacements) |
309 : RewriterBase(replacements), decl_rewriter_(decl_rewriter) {} | |
310 | |
311 void run(const MatchFinder::MatchResult& result) override { | |
312 const clang::CXXMethodDecl* method_decl = | |
313 result.Nodes.getNodeAs<clang::CXXMethodDecl>("decl"); | |
314 if (method_decl->size_overridden_methods() > 0 && | |
315 !decl_rewriter_.IsBlinkOverride(method_decl)) | |
316 return; | |
317 RewriterBase::run(result); | |
212 } | 318 } |
319 | |
320 private: | |
321 const MethodDeclRewriter& decl_rewriter_; | |
213 }; | 322 }; |
214 constexpr char ExprTargetTraits::kName[]; | |
215 | 323 |
216 struct InitializerTargetTraits { | 324 using MethodRefRewriter = FilteringMethodRewriter< |
217 using NodeType = clang::CXXCtorInitializer; | 325 RewriterBase<clang::CXXMethodDecl, clang::DeclRefExpr>>; |
218 static constexpr char kName[] = "initializer"; | 326 using MethodMemberRewriter = FilteringMethodRewriter< |
219 static clang::CharSourceRange GetRange(const NodeType& init) { | 327 RewriterBase<clang::CXXMethodDecl, clang::MemberExpr>>; |
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 | 328 |
242 } // namespace | 329 } // namespace |
243 | 330 |
244 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); | 331 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); |
245 | 332 |
246 int main(int argc, const char* argv[]) { | 333 int main(int argc, const char* argv[]) { |
247 // TODO(dcheng): Clang tooling should do this itself. | 334 // TODO(dcheng): Clang tooling should do this itself. |
248 // http://llvm.org/bugs/show_bug.cgi?id=21627 | 335 // http://llvm.org/bugs/show_bug.cgi?id=21627 |
249 llvm::InitializeNativeTarget(); | 336 llvm::InitializeNativeTarget(); |
250 llvm::InitializeNativeTargetAsmParser(); | 337 llvm::InitializeNativeTargetAsmParser(); |
251 llvm::cl::OptionCategory category( | 338 llvm::cl::OptionCategory category( |
252 "rewrite_to_chrome_style: convert Blink style to Chrome style."); | 339 "rewrite_to_chrome_style: convert Blink style to Chrome style."); |
253 CommonOptionsParser options(argc, argv, category); | 340 CommonOptionsParser options(argc, argv, category); |
254 clang::tooling::ClangTool tool(options.getCompilations(), | 341 clang::tooling::ClangTool tool(options.getCompilations(), |
255 options.getSourcePathList()); | 342 options.getSourcePathList()); |
256 | 343 |
257 MatchFinder match_finder; | 344 MatchFinder match_finder; |
258 Replacements replacements; | 345 Replacements replacements; |
259 | 346 |
260 auto in_blink_namespace = | 347 auto in_blink_namespace = |
261 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); | 348 decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF"))))); |
262 | 349 |
263 // Declaration handling (e.g. function definitions and variable definitions): | 350 // Field and variable declarations ======== |
264 | 351 // Given |
265 // Note: for now, only rewrite standalone functions until the question of JS | 352 // int x; |
266 // binding integration for class methods is resolved. | 353 // struct S { |
267 // TODO(dcheng): Since classes in public/ aren't directly web-exposed, just go | 354 // int y; |
268 // ahead and rewrite those. | 355 // }; |
269 auto function_decl_matcher = | 356 // matches |x| and |y|. |
270 id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace)); | |
271 | |
272 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); | 357 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); |
273 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); | 358 auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); |
274 | 359 |
275 FunctionDeclRewriterCallback function_decl_rewriter(&replacements); | 360 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); | 361 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); |
279 VarDeclRewriterCallback var_decl_rewriter(&replacements); | 362 |
363 VarDeclRewriter var_decl_rewriter(&replacements); | |
280 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); | 364 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); |
281 | 365 |
282 // Expression handling (e.g. calling a Blink function or referencing a | 366 // Field and variable references ======== |
283 // variable defined in Blink): | 367 // Given |
284 auto call_matcher = id("expr", callExpr(callee(function_decl_matcher))); | 368 // bool x = true; |
369 // if (x) { | |
370 // ... | |
371 // } | |
372 // matches |x| in if (x). | |
285 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); | 373 auto member_matcher = id("expr", memberExpr(member(field_decl_matcher))); |
286 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); | 374 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); |
287 | 375 |
288 CallRewriterCallback call_rewriter(&replacements); | 376 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); | 377 match_finder.addMatcher(member_matcher, &member_rewriter); |
292 DeclRefRewriterCallback decl_ref_rewriter(&replacements); | 378 |
379 DeclRefRewriter decl_ref_rewriter(&replacements); | |
293 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); | 380 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); |
294 | 381 |
295 // Function reference handling (e.g. getting a pointer to a function without | 382 // Non-method function declarations ======== |
296 // calling it): | 383 // Given |
384 // void f(); | |
385 // struct S { | |
386 // void g(); | |
387 // }; | |
388 // matches |f| but not |g|. | |
389 auto function_decl_matcher = | |
390 id("decl", functionDecl(unless(cxxMethodDecl()), in_blink_namespace)); | |
391 FunctionDeclRewriter function_decl_rewriter(&replacements); | |
392 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); | |
393 | |
394 // Non-method function references ======== | |
395 // Given | |
396 // f(); | |
397 // void (*p)() = &f; | |
398 // matches |f()| and |&f|. | |
297 auto function_ref_matcher = | 399 auto function_ref_matcher = |
298 id("expr", declRefExpr(to(function_decl_matcher))); | 400 id("expr", declRefExpr(to(function_decl_matcher))); |
299 match_finder.addMatcher(function_ref_matcher, &call_rewriter); | 401 FunctionRefRewriter function_ref_rewriter(&replacements); |
402 match_finder.addMatcher(function_ref_matcher, &function_ref_rewriter); | |
300 | 403 |
301 // Initializer handling: | 404 // Method declarations ======== |
danakj
2016/01/08 02:02:52
I like these comments much
| |
405 // Given | |
406 // struct S { | |
407 // void g(); | |
408 // }; | |
409 // matches |g|. | |
410 // | |
411 // Note: the AST matchers don't provide a good way to match against an | |
412 // override from a given base class. Instead, the rewriter uses two matchers: | |
413 // one that matches all method declarations in the Blink namespace, and | |
414 // another which matches all overridden methods not in the Blink namespace. | |
415 // The second list is filtered against the first list to determine which | |
416 // methods are inherited from Blink classes and need to be rewritten. | |
417 auto blink_method_decl_matcher = | |
418 id("decl", cxxMethodDecl(unless(anyOf( | |
419 // Overloaded operators have special names | |
420 // and should never be renamed. | |
421 isOverloadedOperator(), | |
422 // Similarly, constructors and destructors | |
423 // should not be considered for renaming. | |
424 cxxConstructorDecl(), cxxDestructorDecl())), | |
425 in_blink_namespace)); | |
426 // Note that the matcher for overridden methods doesn't need to filter for | |
427 // special member functions: see implementation of FunctionDeclRewriter for | |
428 // the full explanation. | |
429 auto non_blink_overridden_method_decl_matcher = | |
430 id("decl", cxxMethodDecl(isOverride(), unless(in_blink_namespace))); | |
431 MethodDeclRewriter method_decl_rewriter(&replacements); | |
432 match_finder.addMatcher(blink_method_decl_matcher, &method_decl_rewriter); | |
433 match_finder.addMatcher(non_blink_overridden_method_decl_matcher, | |
434 &method_decl_rewriter); | |
435 | |
436 // Method references in a non-member context ======== | |
437 // Given | |
438 // S s; | |
439 // s.g(); | |
440 // void (S::*p)() = &S::g; | |
441 // matches |&S::g| but not |s.g()|. | |
442 auto blink_method_ref_matcher = | |
443 id("expr", declRefExpr(to(blink_method_decl_matcher))); | |
444 auto non_blink_overridden_method_ref_matcher = | |
445 id("expr", declRefExpr(to(non_blink_overridden_method_decl_matcher))); | |
446 | |
447 MethodRefRewriter method_ref_rewriter(method_decl_rewriter, &replacements); | |
448 match_finder.addMatcher(blink_method_ref_matcher, &method_ref_rewriter); | |
449 match_finder.addMatcher(non_blink_overridden_method_ref_matcher, | |
450 &method_ref_rewriter); | |
451 | |
452 // Method references in a member context ======== | |
453 // Given | |
454 // S s; | |
455 // s.g(); | |
456 // void (S::*p)() = &S::g; | |
457 // matches |s.g()| but not |&S::g|. | |
458 auto blink_method_member_matcher = | |
459 id("expr", memberExpr(member(blink_method_decl_matcher))); | |
460 auto non_blink_overridden_method_member_matcher = | |
461 id("expr", memberExpr(member(non_blink_overridden_method_decl_matcher))); | |
462 | |
463 MethodMemberRewriter method_member_rewriter(method_decl_rewriter, | |
464 &replacements); | |
465 match_finder.addMatcher(blink_method_member_matcher, &method_member_rewriter); | |
466 match_finder.addMatcher(non_blink_overridden_method_member_matcher, | |
467 &method_member_rewriter); | |
468 | |
469 // Initializers ======== | |
470 // Given | |
471 // struct S { | |
472 // int x; | |
473 // S() : x(2) {} | |
474 // }; | |
475 // matches each initializer in the constructor for S. | |
302 auto constructor_initializer_matcher = | 476 auto constructor_initializer_matcher = |
303 cxxConstructorDecl(forEachConstructorInitializer( | 477 cxxConstructorDecl(forEachConstructorInitializer( |
304 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); | 478 id("initializer", cxxCtorInitializer(forField(field_decl_matcher))))); |
305 | 479 |
306 ConstructorInitializerRewriterCallback constructor_initializer_rewriter( | 480 ConstructorInitializerRewriter constructor_initializer_rewriter( |
307 &replacements); | 481 &replacements); |
308 match_finder.addMatcher(constructor_initializer_matcher, | 482 match_finder.addMatcher(constructor_initializer_matcher, |
309 &constructor_initializer_rewriter); | 483 &constructor_initializer_rewriter); |
310 | 484 |
311 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = | 485 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = |
312 clang::tooling::newFrontendActionFactory(&match_finder); | 486 clang::tooling::newFrontendActionFactory(&match_finder); |
313 int result = tool.run(factory.get()); | 487 int result = tool.run(factory.get()); |
314 if (result != 0) | 488 if (result != 0) |
315 return result; | 489 return result; |
316 | 490 |
317 // Serialization format is documented in tools/clang/scripts/run_tool.py | 491 // Serialization format is documented in tools/clang/scripts/run_tool.py |
318 llvm::outs() << "==== BEGIN EDITS ====\n"; | 492 llvm::outs() << "==== BEGIN EDITS ====\n"; |
319 for (const auto& r : replacements) { | 493 for (const auto& r : replacements) { |
320 std::string replacement_text = r.getReplacementText().str(); | 494 std::string replacement_text = r.getReplacementText().str(); |
321 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); | 495 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); |
322 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() | 496 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() |
323 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; | 497 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; |
324 } | 498 } |
325 llvm::outs() << "==== END EDITS ====\n"; | 499 llvm::outs() << "==== END EDITS ====\n"; |
326 | 500 |
327 return 0; | 501 return 0; |
328 } | 502 } |
OLD | NEW |