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
3 // found in the LICENSE file.
4 //
5 // Changes Blink-style names to Chrome-style names. Currently transforms:
6 // fields:
7 // int m_operationCount => int operation_count_
8 // variables (including parameters):
9 // int mySuperVariable => int my_super_variable
10 // constants:
11 // const int maxThings => const int kMaxThings
12 // free functions and methods:
13 // void doThisThenThat() => void DoThisAndThat()
14
15 #include <assert.h>
16 #include <algorithm>
17 #include <memory>
18 #include <set>
19 #include <string>
20
21 #include "clang/AST/ASTContext.h"
22 #include "clang/ASTMatchers/ASTMatchFinder.h"
23 #include "clang/ASTMatchers/ASTMatchers.h"
24 #include "clang/ASTMatchers/ASTMatchersMacros.h"
25 #include "clang/Basic/CharInfo.h"
26 #include "clang/Basic/SourceManager.h"
27 #include "clang/Frontend/CompilerInstance.h"
28 #include "clang/Frontend/FrontendActions.h"
29 #include "clang/Lex/MacroArgs.h"
30 #include "clang/Lex/Lexer.h"
31 #include "clang/Lex/PPCallbacks.h"
32 #include "clang/Lex/Preprocessor.h"
33 #include "clang/Tooling/CommonOptionsParser.h"
34 #include "clang/Tooling/Refactoring.h"
35 #include "clang/Tooling/Tooling.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/TargetSelect.h"
38
39 #include "EditTracker.h"
40
41 using namespace clang::ast_matchers;
42 using clang::tooling::CommonOptionsParser;
43 using clang::tooling::Replacement;
44 using llvm::StringRef;
45
46 namespace {
47
48 const char kBlinkFieldPrefix[] = "m_";
49 const char kBlinkStaticMemberPrefix[] = "s_";
50 const char kGeneratedFileRegex[] = "^gen/|/gen/";
51 const char kGMockMethodNamePrefix[] = "gmock_";
52
53 template <typename MatcherType, typename NodeType>
IsMatching(const MatcherType & matcher,const NodeType & node,clang::ASTContext & context)54 bool IsMatching(const MatcherType& matcher,
55 const NodeType& node,
56 clang::ASTContext& context) {
57 return !match(matcher, node, context).empty();
58 }
59
60 const clang::ast_matchers::internal::
61 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr>
62 unresolvedMemberExpr;
63
64 const clang::ast_matchers::internal::
65 VariadicDynCastAllOfMatcher<clang::Expr, clang::DependentScopeDeclRefExpr>
66 dependentScopeDeclRefExpr;
67
68 const clang::ast_matchers::internal::
69 VariadicDynCastAllOfMatcher<clang::Expr, clang::CXXDependentScopeMemberExpr>
70 cxxDependentScopeMemberExpr;
71
AST_MATCHER(clang::FunctionDecl,isOverloadedOperator)72 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) {
73 return Node.isOverloadedOperator();
74 }
75
AST_MATCHER(clang::CXXMethodDecl,isInstanceMethod)76 AST_MATCHER(clang::CXXMethodDecl, isInstanceMethod) {
77 return Node.isInstance();
78 }
79
AST_MATCHER_P(clang::FunctionTemplateDecl,templatedDecl,clang::ast_matchers::internal::Matcher<clang::FunctionDecl>,InnerMatcher)80 AST_MATCHER_P(clang::FunctionTemplateDecl,
81 templatedDecl,
82 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>,
83 InnerMatcher) {
84 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder);
85 }
86
87 // Matches a CXXMethodDecl of a method declared via MOCK_METHODx macro if such
88 // method mocks a method matched by the InnerMatcher. For example if "foo"
89 // matcher matches "interfaceMethod", then mocksMethod(foo()) will match
90 // "gmock_interfaceMethod" declared by MOCK_METHOD_x(interfaceMethod).
AST_MATCHER_P(clang::CXXMethodDecl,mocksMethod,clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,InnerMatcher)91 AST_MATCHER_P(clang::CXXMethodDecl,
92 mocksMethod,
93 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,
94 InnerMatcher) {
95 if (!Node.getDeclName().isIdentifier())
96 return false;
97
98 llvm::StringRef method_name = Node.getName();
99 if (!method_name.startswith(kGMockMethodNamePrefix))
100 return false;
101
102 llvm::StringRef mocked_method_name =
103 method_name.substr(strlen(kGMockMethodNamePrefix));
104 for (const auto& potentially_mocked_method : Node.getParent()->methods()) {
105 if (!potentially_mocked_method->isVirtual())
106 continue;
107
108 clang::DeclarationName decl_name = potentially_mocked_method->getDeclName();
109 if (!decl_name.isIdentifier() ||
110 potentially_mocked_method->getName() != mocked_method_name)
111 continue;
112 if (potentially_mocked_method->getNumParams() != Node.getNumParams())
113 continue;
114
115 if (InnerMatcher.matches(*potentially_mocked_method, Finder, Builder))
116 return true;
117 }
118
119 return false;
120 }
121
122 // If |InnerMatcher| matches |top|, then the returned matcher will match:
123 // - |top::function|
124 // - |top::Class::method|
125 // - |top::internal::Class::method|
AST_MATCHER_P(clang::NestedNameSpecifier,hasTopLevelPrefix,clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>,InnerMatcher)126 AST_MATCHER_P(
127 clang::NestedNameSpecifier,
128 hasTopLevelPrefix,
129 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>,
130 InnerMatcher) {
131 const clang::NestedNameSpecifier* NodeToMatch = &Node;
132 while (NodeToMatch->getPrefix())
133 NodeToMatch = NodeToMatch->getPrefix();
134 return InnerMatcher.matches(*NodeToMatch, Finder, Builder);
135 }
136
137 // This will narrow CXXCtorInitializers down for both FieldDecls and
138 // IndirectFieldDecls (ie. anonymous unions and such). In both cases
139 // getAnyMember() will return a FieldDecl which we can match against.
AST_MATCHER_P(clang::CXXCtorInitializer,forAnyField,clang::ast_matchers::internal::Matcher<clang::FieldDecl>,InnerMatcher)140 AST_MATCHER_P(clang::CXXCtorInitializer,
141 forAnyField,
142 clang::ast_matchers::internal::Matcher<clang::FieldDecl>,
143 InnerMatcher) {
144 const clang::FieldDecl* NodeAsDecl = Node.getAnyMember();
145 return (NodeAsDecl != nullptr &&
146 InnerMatcher.matches(*NodeAsDecl, Finder, Builder));
147 }
148
149 // Matches if all the overloads in the lookup set match the provided matcher.
AST_MATCHER_P(clang::OverloadExpr,allOverloadsMatch,clang::ast_matchers::internal::Matcher<clang::NamedDecl>,InnerMatcher)150 AST_MATCHER_P(clang::OverloadExpr,
151 allOverloadsMatch,
152 clang::ast_matchers::internal::Matcher<clang::NamedDecl>,
153 InnerMatcher) {
154 if (Node.getNumDecls() == 0)
155 return false;
156
157 for (clang::NamedDecl* decl : Node.decls()) {
158 if (!InnerMatcher.matches(*decl, Finder, Builder))
159 return false;
160 }
161 return true;
162 }
163
PrintForDiagnostics(clang::raw_ostream & os,const clang::FunctionDecl & decl)164 void PrintForDiagnostics(clang::raw_ostream& os,
165 const clang::FunctionDecl& decl) {
166 decl.getLocStart().print(os, decl.getASTContext().getSourceManager());
167 os << ": ";
168 decl.getNameForDiagnostic(os, decl.getASTContext().getPrintingPolicy(), true);
169 }
170
171 template <typename T>
MatchAllOverriddenMethods(const clang::CXXMethodDecl & decl,T && inner_matcher,clang::ast_matchers::internal::ASTMatchFinder * finder,clang::ast_matchers::internal::BoundNodesTreeBuilder * builder)172 bool MatchAllOverriddenMethods(
173 const clang::CXXMethodDecl& decl,
174 T&& inner_matcher,
175 clang::ast_matchers::internal::ASTMatchFinder* finder,
176 clang::ast_matchers::internal::BoundNodesTreeBuilder* builder) {
177 bool override_matches = false;
178 bool override_not_matches = false;
179
180 for (auto it = decl.begin_overridden_methods();
181 it != decl.end_overridden_methods(); ++it) {
182 if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder))
183 override_matches = true;
184 else
185 override_not_matches = true;
186 }
187
188 // If this fires we have a class overriding a method that matches, and a
189 // method that does not match the inner matcher. In that case we will match
190 // one ancestor method but not the other. If we rename one of the and not the
191 // other it will break what this class overrides, disconnecting it from the
192 // one we did not rename which creates a behaviour change. So assert and
193 // demand the user to fix the code first (or add the method to our
194 // blacklist T_T).
195 if (override_matches && override_not_matches) {
196 // blink::InternalSettings::trace method overrides
197 // 1) blink::InternalSettingsGenerated::trace
198 // (won't be renamed because it is in generated code)
199 // 2) blink::Supplement<blink::Page>::trace
200 // (will be renamed).
201 // It is safe to rename blink::InternalSettings::trace, because
202 // both 1 and 2 will both be renamed (#1 via manual changes of the code
203 // generator for DOM bindings and #2 via the clang tool).
204 auto internal_settings_class_decl = cxxRecordDecl(
205 hasName("InternalSettings"),
206 hasParent(namespaceDecl(hasName("blink"),
207 hasParent(translationUnitDecl()))));
208 auto is_method_safe_to_rename = cxxMethodDecl(
209 hasName("trace"),
210 anyOf(hasParent(internal_settings_class_decl), // in .h file
211 has(nestedNameSpecifier(specifiesType( // in .cpp file
212 hasDeclaration(internal_settings_class_decl))))));
213 if (IsMatching(is_method_safe_to_rename, decl, decl.getASTContext()))
214 return true;
215
216 // For previously unknown conflicts, error out and require a human to
217 // analyse the problem (rather than falling back to a potentially unsafe /
218 // code semantics changing rename).
219 llvm::errs() << "ERROR: ";
220 PrintForDiagnostics(llvm::errs(), decl);
221 llvm::errs() << " method overrides "
222 << "some virtual methods that will be automatically renamed "
223 << "and some that won't be renamed.";
224 llvm::errs() << "\n";
225 for (auto it = decl.begin_overridden_methods();
226 it != decl.end_overridden_methods(); ++it) {
227 if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder))
228 llvm::errs() << "Overriden method that will be renamed: ";
229 else
230 llvm::errs() << "Overriden method that will not be renamed: ";
231 PrintForDiagnostics(llvm::errs(), **it);
232 llvm::errs() << "\n";
233 }
234 llvm::errs() << "\n";
235 assert(false);
236 }
237
238 // If the method overrides something that doesn't match, so the method itself
239 // doesn't match.
240 if (override_not_matches)
241 return false;
242
243 // If the method overrides something that matches, so the method ifself
244 // matches.
245 if (override_matches)
246 return true;
247
248 return inner_matcher.matches(decl, finder, builder);
249 }
250
AST_MATCHER_P(clang::CXXMethodDecl,includeAllOverriddenMethods,clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,InnerMatcher)251 AST_MATCHER_P(clang::CXXMethodDecl,
252 includeAllOverriddenMethods,
253 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>,
254 InnerMatcher) {
255 return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder);
256 }
257
258 // Matches |T::m| and/or |x->T::m| and/or |x->m| CXXDependentScopeMemberExpr
259 // if member |m| comes from a type that matches the InnerMatcher.
AST_MATCHER_P(clang::CXXDependentScopeMemberExpr,hasMemberFromType,clang::ast_matchers::internal::Matcher<clang::QualType>,InnerMatcher)260 AST_MATCHER_P(clang::CXXDependentScopeMemberExpr,
261 hasMemberFromType,
262 clang::ast_matchers::internal::Matcher<clang::QualType>,
263 InnerMatcher) {
264 // Given |T::m| and/or |x->T::m| and/or |x->m| ...
265 if (clang::NestedNameSpecifier* nestedNameSpecifier = Node.getQualifier()) {
266 // ... if |T| is present, then InnerMatcher has to match |T|.
267 clang::QualType qualType(nestedNameSpecifier->getAsType(), 0);
268 return InnerMatcher.matches(qualType, Finder, Builder);
269 } else {
270 // ... if there is no |T|, then InnerMatcher has to match the type of |x|.
271 clang::Expr* base_expr = Node.isImplicitAccess() ? nullptr : Node.getBase();
272 return base_expr &&
273 InnerMatcher.matches(base_expr->getType(), Finder, Builder);
274 }
275 }
276
277 // Matches |const Class<T>&| QualType if InnerMatcher matches |Class<T>|.
AST_MATCHER_P(clang::QualType,hasBaseType,clang::ast_matchers::internal::Matcher<clang::Type>,InnerMatcher)278 AST_MATCHER_P(clang::QualType,
279 hasBaseType,
280 clang::ast_matchers::internal::Matcher<clang::Type>,
281 InnerMatcher) {
282 const clang::Type* type = Node.getTypePtrOrNull();
283 return type && InnerMatcher.matches(*type, Finder, Builder);
284 }
285
IsMethodOverrideOf(const clang::CXXMethodDecl & decl,const char * class_name)286 bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl,
287 const char* class_name) {
288 if (decl.getParent()->getQualifiedNameAsString() == class_name)
289 return true;
290 for (auto it = decl.begin_overridden_methods();
291 it != decl.end_overridden_methods(); ++it) {
292 if (IsMethodOverrideOf(**it, class_name))
293 return true;
294 }
295 return false;
296 }
297
IsBlacklistedFunctionName(llvm::StringRef name)298 bool IsBlacklistedFunctionName(llvm::StringRef name) {
299 // https://crbug.com/672902: Method names with an underscore are typically
300 // mimicked after std library / are typically not originating from Blink.
301 // Do not rewrite such names (like push_back, emplace_back, etc.).
302 if (name.find('_') != llvm::StringRef::npos)
303 return true;
304
305 return false;
306 }
307
IsBlacklistedFreeFunctionName(llvm::StringRef name)308 bool IsBlacklistedFreeFunctionName(llvm::StringRef name) {
309 // swap() functions should match the signature of std::swap for ADL tricks.
310 return name == "swap";
311 }
312
IsBlacklistedInstanceMethodName(llvm::StringRef name)313 bool IsBlacklistedInstanceMethodName(llvm::StringRef name) {
314 static const char* kBlacklistedNames[] = {
315 // We should avoid renaming the method names listed below, because
316 // 1. They are used in templated code (e.g. in <algorithms>)
317 // 2. They (begin+end) are used in range-based for syntax sugar
318 // - for (auto x : foo) { ... } // <- foo.begin() will be called.
319 "begin", "end", "rbegin", "rend", "lock", "unlock", "try_lock",
320
321 // https://crbug.com/672902: Should not rewrite names that mimick methods
322 // from std library.
323 "back", "empty", "erase", "front", "insert",
324 };
325 for (const auto& b : kBlacklistedNames) {
326 if (name == b)
327 return true;
328 }
329 return false;
330 }
331
IsBlacklistedMethodName(llvm::StringRef name)332 bool IsBlacklistedMethodName(llvm::StringRef name) {
333 return IsBlacklistedFunctionName(name) ||
334 IsBlacklistedInstanceMethodName(name);
335 }
336
IsBlacklistedFunction(const clang::FunctionDecl & decl)337 bool IsBlacklistedFunction(const clang::FunctionDecl& decl) {
338 clang::StringRef name = decl.getName();
339 return IsBlacklistedFunctionName(name) || IsBlacklistedFreeFunctionName(name);
340 }
341
IsBlacklistedMethod(const clang::CXXMethodDecl & decl)342 bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) {
343 clang::StringRef name = decl.getName();
344 if (IsBlacklistedFunctionName(name))
345 return true;
346
347 // Remaining cases are only applicable to instance methods.
348 if (decl.isStatic())
349 return false;
350
351 if (IsBlacklistedInstanceMethodName(name))
352 return true;
353
354 // Subclasses of InspectorAgent will subclass "disable()" from both blink and
355 // from gen/, which is problematic, but DevTools folks don't want to rename
356 // it or split this up. So don't rename it at all.
357 if (name.equals("disable") &&
358 IsMethodOverrideOf(decl, "blink::InspectorAgent"))
359 return true;
360
361 return false;
362 }
363
AST_MATCHER(clang::FunctionDecl,isBlacklistedFunction)364 AST_MATCHER(clang::FunctionDecl, isBlacklistedFunction) {
365 return IsBlacklistedFunction(Node);
366 }
367
AST_MATCHER(clang::CXXMethodDecl,isBlacklistedMethod)368 AST_MATCHER(clang::CXXMethodDecl, isBlacklistedMethod) {
369 return IsBlacklistedMethod(Node);
370 }
371
372 // Helper to convert from a camelCaseName to camel_case_name. It uses some
373 // heuristics to try to handle acronyms in camel case names correctly.
CamelCaseToUnderscoreCase(StringRef input)374 std::string CamelCaseToUnderscoreCase(StringRef input) {
375 std::string output;
376 bool needs_underscore = false;
377 bool was_lowercase = false;
378 bool was_uppercase = false;
379 bool first_char = true;
380 // Iterate in reverse to minimize the amount of backtracking.
381 for (const unsigned char* i = input.bytes_end() - 1; i >= input.bytes_begin();
382 --i) {
383 char c = *i;
384 bool is_lowercase = clang::isLowercase(c);
385 bool is_uppercase = clang::isUppercase(c);
386 c = clang::toLowercase(c);
387 // Transitioning from upper to lower case requires an underscore. This is
388 // needed to handle names with acronyms, e.g. handledHTTPRequest needs a '_'
389 // in 'dH'. This is a complement to the non-acronym case further down.
390 if (was_uppercase && is_lowercase)
391 needs_underscore = true;
392 if (needs_underscore) {
393 output += '_';
394 needs_underscore = false;
395 }
396 output += c;
397 // Handles the non-acronym case: transitioning from lower to upper case
398 // requires an underscore when emitting the next character, e.g. didLoad
399 // needs a '_' in 'dL'.
400 if (!first_char && was_lowercase && is_uppercase)
401 needs_underscore = true;
402 was_lowercase = is_lowercase;
403 was_uppercase = is_uppercase;
404 first_char = false;
405 }
406 std::reverse(output.begin(), output.end());
407 return output;
408 }
409
CanBeEvaluatedAtCompileTime(const clang::Stmt * stmt,const clang::ASTContext & context)410 bool CanBeEvaluatedAtCompileTime(const clang::Stmt* stmt,
411 const clang::ASTContext& context) {
412 auto* expr = clang::dyn_cast<clang::Expr>(stmt);
413 if (!expr) {
414 // If the statement is not an expression then it's a constant.
415 return true;
416 }
417
418 // Function calls create non-consistent behaviour. For some template
419 // instantiations they can be constexpr while for others they are not, which
420 // changes the output of isEvaluatable().
421 if (expr->hasNonTrivialCall(context))
422 return false;
423
424 // Recurse on children. If they are all const (or are uses of template
425 // input) then the statement can be considered const. For whatever reason the
426 // below checks can give different-and-less-consistent responses if we call
427 // them on a complex expression than if we call them on the most primitive
428 // pieces (some pieces would say false but the whole thing says true).
429 for (auto* child : expr->children()) {
430 if (!CanBeEvaluatedAtCompileTime(child, context))
431 return false;
432 }
433
434 // If the expression depends on template input, we can not call
435 // isEvaluatable() on it as it will do bad things/crash.
436 if (!expr->isInstantiationDependent()) {
437 // If the expression can be evaluated at compile time, then it should have a
438 // kFoo style name. Otherwise, not.
439 return expr->isEvaluatable(context);
440 }
441
442 // We do our best to figure out special cases as we come across them here, for
443 // template dependent situations. Some cases in code are only considered
444 // instantiation dependent for some template instantiations! Which is
445 // terrible! So most importantly we try to match isEvaluatable in those cases.
446 switch (expr->getStmtClass()) {
447 case clang::Stmt::CXXThisExprClass:
448 return false;
449 case clang::Stmt::DeclRefExprClass: {
450 auto* declref = clang::dyn_cast<clang::DeclRefExpr>(expr);
451 auto* decl = declref->getDecl();
452 if (auto* vardecl = clang::dyn_cast<clang::VarDecl>(decl)) {
453 if (auto* initializer = vardecl->getInit())
454 return CanBeEvaluatedAtCompileTime(initializer, context);
455 return false;
456 }
457 break;
458 }
459
460 default:
461 break;
462 }
463
464 // Otherwise, we consider depending on template parameters to not interfere
465 // with being const.. with exceptions hopefully covered above.
466 return true;
467 }
468
IsProbablyConst(const clang::VarDecl & decl,const clang::ASTContext & context)469 bool IsProbablyConst(const clang::VarDecl& decl,
470 const clang::ASTContext& context) {
471 clang::QualType type = decl.getType();
472 if (!type.isConstQualified())
473 return false;
474
475 if (type.isVolatileQualified())
476 return false;
477
478 if (decl.isConstexpr())
479 return true;
480
481 // Parameters should not be renamed to |kFooBar| style (even if they are
482 // const and have an initializer (aka default value)).
483 if (clang::isa<clang::ParmVarDecl>(&decl))
484 return false;
485
486 // http://google.github.io/styleguide/cppguide.html#Constant_Names
487 // Static variables that are const-qualified should use kConstantStyle naming.
488 if (decl.getStorageDuration() == clang::SD_Static)
489 return true;
490
491 const clang::Expr* initializer = decl.getInit();
492 if (!initializer)
493 return false;
494
495 return CanBeEvaluatedAtCompileTime(initializer, context);
496 }
497
AST_MATCHER_P(clang::QualType,hasString,std::string,ExpectedString)498 AST_MATCHER_P(clang::QualType, hasString, std::string, ExpectedString) {
499 return ExpectedString == Node.getAsString();
500 }
501
ShouldPrefixFunctionName(const std::string & old_method_name)502 bool ShouldPrefixFunctionName(const std::string& old_method_name) {
503 // Functions that are named similarily to a type - they should be prefixed
504 // with a "Get" prefix.
505 static const char* kConflictingMethods[] = {
506 "animationWorklet",
507 "audioWorklet",
508 "binaryType",
509 "blob",
510 "channelCountMode",
511 "color",
512 "counterDirectives",
513 "document",
514 "emptyChromeClient",
515 "emptyEditorClient",
516 "emptySpellCheckerClient",
517 "entryType",
518 "error",
519 "fileUtilities",
520 "font",
521 "frame",
522 "frameBlameContext",
523 "frontend",
524 "hash",
525 "heapObjectHeader",
526 "iconURL",
527 "inputMethodController",
528 "inputType",
529 "layout",
530 "layoutBlock",
531 "layoutObject",
532 "layoutSize",
533 "length",
534 "lineCap",
535 "lineEndings",
536 "lineJoin",
537 "listItems",
538 "matchedProperties",
539 "midpointState",
540 "mouseEvent",
541 "name",
542 "navigationType",
543 "node",
544 "outcome",
545 "pagePopup",
546 "paintWorklet",
547 "path",
548 "processingInstruction",
549 "readyState",
550 "relList",
551 "resource",
552 "response",
553 "sandboxSupport",
554 "screenInfo",
555 "scrollAnimator",
556 "settings",
557 "signalingState",
558 "state",
559 "string",
560 "styleSheet",
561 "text",
562 "textAlign",
563 "textBaseline",
564 "theme",
565 "thread",
566 "timing",
567 "topLevelBlameContext",
568 "vector",
569 "widget",
570 "wordBoundaries",
571 "wrapperTypeInfo",
572 };
573 for (const auto& conflicting_method : kConflictingMethods) {
574 if (old_method_name == conflicting_method)
575 return true;
576 }
577
578 return false;
579 }
580
AST_MATCHER(clang::FunctionDecl,shouldPrefixFunctionName)581 AST_MATCHER(clang::FunctionDecl, shouldPrefixFunctionName) {
582 return ShouldPrefixFunctionName(Node.getName().str());
583 }
584
GetNameForDecl(const clang::FunctionDecl & decl,clang::ASTContext & context,std::string & name)585 bool GetNameForDecl(const clang::FunctionDecl& decl,
586 clang::ASTContext& context,
587 std::string& name) {
588 name = decl.getName().str();
589 name[0] = clang::toUppercase(name[0]);
590
591 // Given
592 // class Foo {};
593 // class DerivedFoo : class Foo;
594 // using Bar = Foo;
595 // Bar f1(); // <- |Bar| would be matched by hasString("Bar") below.
596 // Bar f2(); // <- |Bar| would be matched by hasName("Foo") below.
597 // DerivedFoo f3(); // <- |DerivedFoo| matched by isDerivedFrom(...) below.
598 // |type_with_same_name_as_function| matcher matches Bar and Foo return types.
599 auto type_with_same_name_as_function = qualType(anyOf(
600 // hasString matches the type as spelled (Bar above).
601 hasString(name),
602 // hasDeclaration matches resolved type (Foo or DerivedFoo above).
603 hasDeclaration(namedDecl(hasName(name)))));
604
605 // |type_containing_same_name_as_function| matcher will match all of the
606 // return types below:
607 // - Foo foo() // Direct application of |type_with_same_name_as_function|.
608 // - Foo* foo() // |hasDescendant| traverses references/pointers.
609 // - RefPtr<Foo> foo() // |hasDescendant| traverses template arguments.
610 auto type_containing_same_name_as_function =
611 qualType(anyOf(type_with_same_name_as_function,
612 hasDescendant(type_with_same_name_as_function)));
613 // https://crbug.com/582312: Prepend "Get" if method name conflicts with
614 // return type.
615 auto conflict_matcher = functionDecl(anyOf(
616 // For functions and non-virtual or base method implementations just
617 // compare with the immediate return type.
618 functionDecl(returns(type_containing_same_name_as_function),
619 unless(cxxMethodDecl(isOverride()))),
620 // For methods that override one or more methods, compare with the return
621 // type of the *base* methods.
622 cxxMethodDecl(isOverride(), forEachOverridden(returns(
623 type_containing_same_name_as_function))),
624 // And also check hardcoded list of function names to prefix with "Get".
625 shouldPrefixFunctionName()));
626 if (IsMatching(conflict_matcher, decl, context))
627 name = "Get" + name;
628
629 return true;
630 }
631
GetNameForDecl(const clang::EnumConstantDecl & decl,clang::ASTContext & context,std::string & name)632 bool GetNameForDecl(const clang::EnumConstantDecl& decl,
633 clang::ASTContext& context,
634 std::string& name) {
635 StringRef original_name = decl.getName();
636
637 // If it's already correct leave it alone.
638 if (original_name.size() >= 2 && original_name[0] == 'k' &&
639 clang::isUppercase(original_name[1]))
640 return false;
641
642 bool is_shouty = true;
643 for (char c : original_name) {
644 if (!clang::isUppercase(c) && !clang::isDigit(c) && c != '_') {
645 is_shouty = false;
646 break;
647 }
648 }
649
650 if (is_shouty)
651 return false;
652
653 name = 'k'; // k prefix on enum values.
654 name += original_name;
655 name[1] = clang::toUppercase(name[1]);
656 return true;
657 }
658
GetNameForDecl(const clang::FieldDecl & decl,clang::ASTContext & context,std::string & name)659 bool GetNameForDecl(const clang::FieldDecl& decl,
660 clang::ASTContext& context,
661 std::string& name) {
662 StringRef original_name = decl.getName();
663 bool member_prefix = original_name.startswith(kBlinkFieldPrefix);
664
665 StringRef rename_part = !member_prefix
666 ? original_name
667 : original_name.substr(strlen(kBlinkFieldPrefix));
668 name = CamelCaseToUnderscoreCase(rename_part);
669
670 // Assume that prefix of m_ was intentional and always replace it with a
671 // suffix _.
672 if (member_prefix && name.back() != '_')
673 name += '_';
674
675 return true;
676 }
677
GetNameForDecl(const clang::VarDecl & decl,clang::ASTContext & context,std::string & name)678 bool GetNameForDecl(const clang::VarDecl& decl,
679 clang::ASTContext& context,
680 std::string& name) {
681 StringRef original_name = decl.getName();
682
683 // Nothing to do for unnamed parameters.
684 if (clang::isa<clang::ParmVarDecl>(decl)) {
685 if (original_name.empty())
686 return false;
687
688 // Check if |decl| and |decl.getLocation| are in sync. We need to skip
689 // out-of-sync ParmVarDecls to avoid renaming buggy ParmVarDecls that
690 // 1) have decl.getLocation() pointing at a parameter declaration without a
691 // name, but 2) have decl.getName() retained from a template specialization
692 // of a method. See also: https://llvm.org/bugs/show_bug.cgi?id=29145
693 clang::SourceLocation loc =
694 context.getSourceManager().getSpellingLoc(decl.getLocation());
695 auto parents = context.getParents(decl);
696 bool is_child_location_within_parent_source_range = std::all_of(
697 parents.begin(), parents.end(),
698 [&loc](const clang::ast_type_traits::DynTypedNode& parent) {
699 clang::SourceLocation begin = parent.getSourceRange().getBegin();
700 clang::SourceLocation end = parent.getSourceRange().getEnd();
701 return (begin < loc) && (loc < end);
702 });
703 if (!is_child_location_within_parent_source_range)
704 return false;
705 }
706
707 // static class members match against VarDecls. Blink style dictates that
708 // these should be prefixed with `s_`, so strip that off. Also check for `m_`
709 // and strip that off too, for code that accidentally uses the wrong prefix.
710 if (original_name.startswith(kBlinkStaticMemberPrefix))
711 original_name = original_name.substr(strlen(kBlinkStaticMemberPrefix));
712 else if (original_name.startswith(kBlinkFieldPrefix))
713 original_name = original_name.substr(strlen(kBlinkFieldPrefix));
714
715 bool is_const = IsProbablyConst(decl, context);
716 if (is_const) {
717 // Don't try to rename constants that already conform to Chrome style.
718 if (original_name.size() >= 2 && original_name[0] == 'k' &&
719 clang::isUppercase(original_name[1]))
720 return false;
721 // Or names are spelt with underscore casing. While they are actually
722 // compile consts, the author wrote it explicitly as a variable not as
723 // a constant (they would have used kFormat otherwise here), so preserve
724 // it rather than try to mangle a kFormat out of it.
725 if (original_name.find('_') != StringRef::npos)
726 return false;
727
728 name = 'k';
729 name.append(original_name.data(), original_name.size());
730 name[1] = clang::toUppercase(name[1]);
731 } else {
732 name = CamelCaseToUnderscoreCase(original_name);
733
734 // Non-const variables with static storage duration at namespace scope are
735 // prefixed with `g_' to reduce the likelihood of a naming collision.
736 const clang::DeclContext* decl_context = decl.getDeclContext();
737 if (name.find("g_") != 0 && decl.hasGlobalStorage() &&
738 decl_context->isNamespace())
739 name.insert(0, "g_");
740 }
741
742 // Static members end with _ just like other members, but constants should
743 // not.
744 if (!is_const && decl.isStaticDataMember()) {
745 name += '_';
746 }
747
748 return true;
749 }
750
GetNameForDecl(const clang::FunctionTemplateDecl & decl,clang::ASTContext & context,std::string & name)751 bool GetNameForDecl(const clang::FunctionTemplateDecl& decl,
752 clang::ASTContext& context,
753 std::string& name) {
754 clang::FunctionDecl* templated_function = decl.getTemplatedDecl();
755 return GetNameForDecl(*templated_function, context, name);
756 }
757
GetNameForDecl(const clang::NamedDecl & decl,clang::ASTContext & context,std::string & name)758 bool GetNameForDecl(const clang::NamedDecl& decl,
759 clang::ASTContext& context,
760 std::string& name) {
761 if (auto* function = clang::dyn_cast<clang::FunctionDecl>(&decl))
762 return GetNameForDecl(*function, context, name);
763 if (auto* var = clang::dyn_cast<clang::VarDecl>(&decl))
764 return GetNameForDecl(*var, context, name);
765 if (auto* field = clang::dyn_cast<clang::FieldDecl>(&decl))
766 return GetNameForDecl(*field, context, name);
767 if (auto* function_template =
768 clang::dyn_cast<clang::FunctionTemplateDecl>(&decl))
769 return GetNameForDecl(*function_template, context, name);
770 if (auto* enumc = clang::dyn_cast<clang::EnumConstantDecl>(&decl))
771 return GetNameForDecl(*enumc, context, name);
772
773 return false;
774 }
775
GetNameForDecl(const clang::UsingDecl & decl,clang::ASTContext & context,std::string & name)776 bool GetNameForDecl(const clang::UsingDecl& decl,
777 clang::ASTContext& context,
778 std::string& name) {
779 assert(decl.shadow_size() > 0);
780
781 // If a using declaration's targeted declaration is a set of overloaded
782 // functions, it can introduce multiple shadowed declarations. Just using the
783 // first one is OK, since overloaded functions have the same name, by
784 // definition.
785 return GetNameForDecl(*decl.shadow_begin()->getTargetDecl(), context, name);
786 }
787
788 template <typename Type>
789 struct TargetNodeTraits;
790
791 template <>
792 struct TargetNodeTraits<clang::NamedDecl> {
GetLoc__anon6b399b860111::TargetNodeTraits793 static clang::SourceLocation GetLoc(const clang::NamedDecl& decl) {
794 return decl.getLocation();
795 }
GetName__anon6b399b860111::TargetNodeTraits796 static const char* GetName() { return "decl"; }
GetType__anon6b399b860111::TargetNodeTraits797 static const char* GetType() { return "NamedDecl"; }
798 };
799
800 template <>
801 struct TargetNodeTraits<clang::MemberExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits802 static clang::SourceLocation GetLoc(const clang::MemberExpr& expr) {
803 return expr.getMemberLoc();
804 }
GetName__anon6b399b860111::TargetNodeTraits805 static const char* GetName() { return "expr"; }
GetType__anon6b399b860111::TargetNodeTraits806 static const char* GetType() { return "MemberExpr"; }
807 };
808
809 template <>
810 struct TargetNodeTraits<clang::DeclRefExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits811 static clang::SourceLocation GetLoc(const clang::DeclRefExpr& expr) {
812 return expr.getLocation();
813 }
GetName__anon6b399b860111::TargetNodeTraits814 static const char* GetName() { return "expr"; }
GetType__anon6b399b860111::TargetNodeTraits815 static const char* GetType() { return "DeclRefExpr"; }
816 };
817
818 template <>
819 struct TargetNodeTraits<clang::DependentScopeDeclRefExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits820 static clang::SourceLocation GetLoc(
821 const clang::DependentScopeDeclRefExpr& expr) {
822 return expr.getLocation();
823 }
GetName__anon6b399b860111::TargetNodeTraits824 static const char* GetName() { return "expr"; }
825 };
826
827 template <>
828 struct TargetNodeTraits<clang::CXXDependentScopeMemberExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits829 static clang::SourceLocation GetLoc(
830 const clang::CXXDependentScopeMemberExpr& expr) {
831 return expr.getMemberLoc();
832 }
GetName__anon6b399b860111::TargetNodeTraits833 static const char* GetName() { return "expr"; }
834 };
835
836 template <>
837 struct TargetNodeTraits<clang::CXXCtorInitializer> {
GetLoc__anon6b399b860111::TargetNodeTraits838 static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) {
839 assert(init.isWritten());
840 return init.getSourceLocation();
841 }
GetName__anon6b399b860111::TargetNodeTraits842 static const char* GetName() { return "initializer"; }
GetType__anon6b399b860111::TargetNodeTraits843 static const char* GetType() { return "CXXCtorInitializer"; }
844 };
845
846 template <>
847 struct TargetNodeTraits<clang::UnresolvedLookupExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits848 static clang::SourceLocation GetLoc(const clang::UnresolvedLookupExpr& expr) {
849 return expr.getNameLoc();
850 }
GetName__anon6b399b860111::TargetNodeTraits851 static const char* GetName() { return "expr"; }
GetType__anon6b399b860111::TargetNodeTraits852 static const char* GetType() { return "UnresolvedLookupExpr"; }
853 };
854
855 template <>
856 struct TargetNodeTraits<clang::UnresolvedMemberExpr> {
GetLoc__anon6b399b860111::TargetNodeTraits857 static clang::SourceLocation GetLoc(const clang::UnresolvedMemberExpr& expr) {
858 return expr.getMemberLoc();
859 }
GetName__anon6b399b860111::TargetNodeTraits860 static const char* GetName() { return "expr"; }
GetType__anon6b399b860111::TargetNodeTraits861 static const char* GetType() { return "UnresolvedMemberExpr"; }
862 };
863
864 template <>
865 struct TargetNodeTraits<clang::UnresolvedUsingValueDecl> {
GetLoc__anon6b399b860111::TargetNodeTraits866 static clang::SourceLocation GetLoc(
867 const clang::UnresolvedUsingValueDecl& decl) {
868 return decl.getNameInfo().getLoc();
869 }
GetName__anon6b399b860111::TargetNodeTraits870 static const char* GetName() { return "decl"; }
GetType__anon6b399b860111::TargetNodeTraits871 static const char* GetType() { return "UnresolvedUsingValueDecl"; }
872 };
873
874 template <typename TargetNode>
875 class RewriterBase : public MatchFinder::MatchCallback {
876 public:
RewriterBase(std::set<Replacement> * replacements)877 explicit RewriterBase(std::set<Replacement>* replacements)
878 : replacements_(replacements) {}
879
GetTargetNode(const MatchFinder::MatchResult & result)880 const TargetNode& GetTargetNode(const MatchFinder::MatchResult& result) {
881 const TargetNode* target_node = result.Nodes.getNodeAs<TargetNode>(
882 TargetNodeTraits<TargetNode>::GetName());
883 assert(target_node);
884 return *target_node;
885 }
886
GenerateReplacement(const MatchFinder::MatchResult & result,clang::SourceLocation loc,llvm::StringRef old_name,std::string new_name,Replacement * replacement)887 bool GenerateReplacement(const MatchFinder::MatchResult& result,
888 clang::SourceLocation loc,
889 llvm::StringRef old_name,
890 std::string new_name,
891 Replacement* replacement) {
892 const clang::ASTContext& context = *result.Context;
893 const clang::SourceManager& source_manager = *result.SourceManager;
894
895 if (loc.isMacroID()) {
896 // Try to jump "above" the scratch buffer if |loc| is inside
897 // token##Concatenation.
898 const int kMaxJumps = 5;
899 bool verified_out_of_scratch_space = false;
900 for (int i = 0; i < kMaxJumps && !verified_out_of_scratch_space; i++) {
901 clang::SourceLocation spell = source_manager.getSpellingLoc(loc);
902 verified_out_of_scratch_space =
903 source_manager.getBufferName(spell) != "<scratch space>";
904 if (!verified_out_of_scratch_space)
905 loc = source_manager.getImmediateMacroCallerLoc(loc);
906 }
907 if (!verified_out_of_scratch_space)
908 return false;
909 }
910
911 // If the edit affects only the first character of the identifier, then
912 // narrow down the edit to only this single character. This is important
913 // for dealing with toFooBar -> ToFooBar method renaming when the method
914 // name is built using macro token concatenation like to##macroArgument - in
915 // this case we should only rewrite "t" -> "T" and leave "o##macroArgument"
916 // untouched.
917 llvm::StringRef expected_old_text = old_name;
918 llvm::StringRef new_text = new_name;
919 if (loc.isMacroID() && expected_old_text.substr(1) == new_text.substr(1)) {
920 expected_old_text = expected_old_text.substr(0, 1);
921 new_text = new_text.substr(0, 1);
922 }
923 clang::SourceLocation spell = source_manager.getSpellingLoc(loc);
924 clang::CharSourceRange range = clang::CharSourceRange::getCharRange(
925 spell, spell.getLocWithOffset(expected_old_text.size()));
926
927 // We need to ensure that |actual_old_text| is the same as
928 // |expected_old_text| - it can be different if |actual_old_text| contains
929 // a macro argument (see DEFINE_WITH_TOKEN_CONCATENATION2 in
930 // macros-original.cc testcase).
931 StringRef actual_old_text = clang::Lexer::getSourceText(
932 range, source_manager, context.getLangOpts());
933 if (actual_old_text != expected_old_text)
934 return false;
935
936 if (replacement)
937 *replacement = Replacement(source_manager, range, new_text);
938 return true;
939 }
940
GetTargetLoc(const MatchFinder::MatchResult & result)941 virtual clang::SourceLocation GetTargetLoc(
942 const MatchFinder::MatchResult& result) {
943 return TargetNodeTraits<TargetNode>::GetLoc(GetTargetNode(result));
944 }
945
AddReplacement(const MatchFinder::MatchResult & result,llvm::StringRef old_name,std::string new_name)946 void AddReplacement(const MatchFinder::MatchResult& result,
947 llvm::StringRef old_name,
948 std::string new_name) {
949 if (old_name == new_name)
950 return;
951
952 clang::SourceLocation loc = GetTargetLoc(result);
953 if (loc.isInvalid())
954 return;
955
956 Replacement replacement;
957 if (!GenerateReplacement(result, loc, old_name, new_name, &replacement))
958 return;
959
960 replacements_->insert(std::move(replacement));
961 edit_tracker_.Add(*result.SourceManager, loc, old_name, new_name);
962 }
963
edit_tracker() const964 const EditTracker& edit_tracker() const { return edit_tracker_; }
965
966 private:
967 std::set<Replacement>* const replacements_;
968 EditTracker edit_tracker_;
969 };
970
971 template <typename DeclNode, typename TargetNode>
972 class DeclRewriterBase : public RewriterBase<TargetNode> {
973 public:
974 using Base = RewriterBase<TargetNode>;
975
DeclRewriterBase(std::set<Replacement> * replacements)976 explicit DeclRewriterBase(std::set<Replacement>* replacements)
977 : Base(replacements) {}
978
run(const MatchFinder::MatchResult & result)979 void run(const MatchFinder::MatchResult& result) override {
980 const DeclNode* decl = result.Nodes.getNodeAs<DeclNode>("decl");
981 assert(decl);
982 llvm::StringRef old_name = decl->getName();
983
984 // Return early if there's no name to be renamed.
985 if (!decl->getIdentifier())
986 return;
987
988 // Get the new name.
989 std::string new_name;
990 if (!GetNameForDecl(*decl, *result.Context, new_name))
991 return; // If false, the name was not suitable for renaming.
992
993 // Check if we are able to rewrite the decl (to avoid rewriting if the
994 // decl's identifier is part of macro##Token##Concatenation).
995 clang::SourceLocation decl_loc =
996 TargetNodeTraits<clang::NamedDecl>::GetLoc(*decl);
997 if (!Base::GenerateReplacement(result, decl_loc, old_name, new_name,
998 nullptr))
999 return;
1000
1001 Base::AddReplacement(result, old_name, std::move(new_name));
1002 }
1003 };
1004
1005 using FieldDeclRewriter = DeclRewriterBase<clang::FieldDecl, clang::NamedDecl>;
1006 using VarDeclRewriter = DeclRewriterBase<clang::VarDecl, clang::NamedDecl>;
1007 using MemberRewriter = DeclRewriterBase<clang::FieldDecl, clang::MemberExpr>;
1008 using DeclRefRewriter = DeclRewriterBase<clang::VarDecl, clang::DeclRefExpr>;
1009 using FieldDeclRefRewriter =
1010 DeclRewriterBase<clang::FieldDecl, clang::DeclRefExpr>;
1011 using FunctionDeclRewriter =
1012 DeclRewriterBase<clang::FunctionDecl, clang::NamedDecl>;
1013 using FunctionRefRewriter =
1014 DeclRewriterBase<clang::FunctionDecl, clang::DeclRefExpr>;
1015 using ConstructorInitializerRewriter =
1016 DeclRewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>;
1017
1018 using MethodDeclRewriter =
1019 DeclRewriterBase<clang::CXXMethodDecl, clang::NamedDecl>;
1020 using MethodRefRewriter =
1021 DeclRewriterBase<clang::CXXMethodDecl, clang::DeclRefExpr>;
1022 using MethodMemberRewriter =
1023 DeclRewriterBase<clang::CXXMethodDecl, clang::MemberExpr>;
1024
1025 using EnumConstantDeclRewriter =
1026 DeclRewriterBase<clang::EnumConstantDecl, clang::NamedDecl>;
1027 using EnumConstantDeclRefRewriter =
1028 DeclRewriterBase<clang::EnumConstantDecl, clang::DeclRefExpr>;
1029
1030 using UnresolvedLookupRewriter =
1031 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedLookupExpr>;
1032 using UnresolvedMemberRewriter =
1033 DeclRewriterBase<clang::NamedDecl, clang::UnresolvedMemberExpr>;
1034
1035 using UsingDeclRewriter = DeclRewriterBase<clang::UsingDecl, clang::NamedDecl>;
1036
1037 class GMockMemberRewriter
1038 : public DeclRewriterBase<clang::CXXMethodDecl, clang::MemberExpr> {
1039 public:
1040 using Base = DeclRewriterBase<clang::CXXMethodDecl, clang::MemberExpr>;
1041
GMockMemberRewriter(std::set<Replacement> * replacements)1042 explicit GMockMemberRewriter(std::set<Replacement>* replacements)
1043 : Base(replacements) {}
1044
CreatePreprocessorCallbacks()1045 std::unique_ptr<clang::PPCallbacks> CreatePreprocessorCallbacks() {
1046 return llvm::make_unique<GMockMemberRewriter::PPCallbacks>(this);
1047 }
1048
GetTargetLoc(const MatchFinder::MatchResult & result)1049 clang::SourceLocation GetTargetLoc(
1050 const MatchFinder::MatchResult& result) override {
1051 // Find location of the gmock_##MockedMethod identifier.
1052 clang::SourceLocation target_loc = Base::GetTargetLoc(result);
1053
1054 // Find location of EXPECT_CALL macro invocation.
1055 clang::SourceLocation macro_call_loc =
1056 result.SourceManager->getExpansionLoc(target_loc);
1057
1058 // Map |macro_call_loc| to argument location (location of the method name
1059 // that needs renaming).
1060 auto it = expect_call_to_2nd_arg.find(macro_call_loc);
1061 if (it == expect_call_to_2nd_arg.end())
1062 return clang::SourceLocation();
1063 return it->second;
1064 }
1065
1066 private:
1067 std::map<clang::SourceLocation, clang::SourceLocation> expect_call_to_2nd_arg;
1068
1069 // Called from PPCallbacks with the locations of EXPECT_CALL macro invocation:
1070 // Example:
1071 // EXPECT_CALL(my_mock, myMethod(123, 456));
1072 // ^- expansion_loc ^- actual_arg_loc
RecordExpectCallMacroInvocation(clang::SourceLocation expansion_loc,clang::SourceLocation second_arg_loc)1073 void RecordExpectCallMacroInvocation(clang::SourceLocation expansion_loc,
1074 clang::SourceLocation second_arg_loc) {
1075 expect_call_to_2nd_arg[expansion_loc] = second_arg_loc;
1076 }
1077
1078 class PPCallbacks : public clang::PPCallbacks {
1079 public:
PPCallbacks(GMockMemberRewriter * rewriter)1080 explicit PPCallbacks(GMockMemberRewriter* rewriter) : rewriter_(rewriter) {}
~PPCallbacks()1081 ~PPCallbacks() override {}
MacroExpands(const clang::Token & name,const clang::MacroDefinition & def,clang::SourceRange range,const clang::MacroArgs * args)1082 void MacroExpands(const clang::Token& name,
1083 const clang::MacroDefinition& def,
1084 clang::SourceRange range,
1085 const clang::MacroArgs* args) override {
1086 clang::IdentifierInfo* id = name.getIdentifierInfo();
1087 if (!id)
1088 return;
1089
1090 if (id->getName() != "EXPECT_CALL")
1091 return;
1092
1093 if (def.getMacroInfo()->getNumArgs() != 2)
1094 return;
1095
1096 // TODO(lukasza): Should check if def.getMacroInfo()->getDefinitionLoc()
1097 // is in testing/gmock/include/gmock/gmock-spec-builders.h but I don't
1098 // know how to get clang::SourceManager to call getFileName.
1099
1100 rewriter_->RecordExpectCallMacroInvocation(
1101 name.getLocation(), args->getUnexpArgument(1)->getLocation());
1102 }
1103
1104 private:
1105 GMockMemberRewriter* rewriter_;
1106 };
1107 };
1108
GetUnresolvedName(const clang::UnresolvedMemberExpr & expr)1109 clang::DeclarationName GetUnresolvedName(
1110 const clang::UnresolvedMemberExpr& expr) {
1111 return expr.getMemberName();
1112 }
1113
GetUnresolvedName(const clang::DependentScopeDeclRefExpr & expr)1114 clang::DeclarationName GetUnresolvedName(
1115 const clang::DependentScopeDeclRefExpr& expr) {
1116 return expr.getDeclName();
1117 }
1118
GetUnresolvedName(const clang::CXXDependentScopeMemberExpr & expr)1119 clang::DeclarationName GetUnresolvedName(
1120 const clang::CXXDependentScopeMemberExpr& expr) {
1121 return expr.getMember();
1122 }
1123
GetUnresolvedName(const clang::UnresolvedUsingValueDecl & decl)1124 clang::DeclarationName GetUnresolvedName(
1125 const clang::UnresolvedUsingValueDecl& decl) {
1126 return decl.getDeclName();
1127 }
1128
1129 // Returns whether |expr_node| is used as a callee in the AST (i.e. if
1130 // |expr_node| needs to resolve to a method or a function).
IsCallee(const clang::Expr & expr,clang::ASTContext & context)1131 bool IsCallee(const clang::Expr& expr, clang::ASTContext& context) {
1132 auto matcher = stmt(hasParent(callExpr(callee(equalsNode(&expr)))));
1133 return IsMatching(matcher, expr, context);
1134 }
1135
1136 // Returns whether |decl| will be used as a callee in the AST (i.e. if the value
1137 // brought by the using declaration will resolve to a method or a function).
IsCallee(const clang::UnresolvedUsingValueDecl & decl,clang::ASTContext &)1138 bool IsCallee(const clang::UnresolvedUsingValueDecl& decl,
1139 clang::ASTContext& /* context */) {
1140 // Caller (i.e. GuessNameForUnresolvedDependentNode) should have already
1141 // filtered out fields before calling |IsCallee|.
1142 clang::IdentifierInfo* info = GetUnresolvedName(decl).getAsIdentifierInfo();
1143 assert(info);
1144 bool name_looks_like_a_field = info->getName().startswith(kBlinkFieldPrefix);
1145 assert(!name_looks_like_a_field);
1146
1147 // Looking just at clang::UnresolvedUsingValueDecl, we cannot tell whether it
1148 // refers to something callable or not. Since fields should have been already
1149 // filtered out before calling IsCallee (see the assert above), let's assume
1150 // that |using Base::foo| refers to a method.
1151 return true;
1152 }
1153
1154 template <typename TargetNode>
1155 class UnresolvedRewriterBase : public RewriterBase<TargetNode> {
1156 public:
1157 using Base = RewriterBase<TargetNode>;
1158
UnresolvedRewriterBase(std::set<Replacement> * replacements)1159 explicit UnresolvedRewriterBase(std::set<Replacement>* replacements)
1160 : RewriterBase<TargetNode>(replacements) {}
1161
run(const MatchFinder::MatchResult & result)1162 void run(const MatchFinder::MatchResult& result) override {
1163 const TargetNode& node = Base::GetTargetNode(result);
1164
1165 clang::DeclarationName decl_name = GetUnresolvedName(node);
1166 switch (decl_name.getNameKind()) {
1167 // Do not rewrite this:
1168 // return operator T*();
1169 // into this:
1170 // return Operator type - parameter - 0 - 0 * T * ();
1171 case clang::DeclarationName::NameKind::CXXConversionFunctionName:
1172 case clang::DeclarationName::NameKind::CXXOperatorName:
1173 case clang::DeclarationName::NameKind::CXXLiteralOperatorName:
1174 return;
1175 default:
1176 break;
1177 }
1178
1179 // Make sure there is an old name + extract the old name.
1180 clang::IdentifierInfo* info = GetUnresolvedName(node).getAsIdentifierInfo();
1181 if (!info)
1182 return;
1183 llvm::StringRef old_name = info->getName();
1184
1185 // Try to guess a new name.
1186 std::string new_name;
1187 if (GuessNameForUnresolvedDependentNode(node, *result.Context, old_name,
1188 new_name))
1189 Base::AddReplacement(result, old_name, std::move(new_name));
1190 }
1191
1192 private:
1193 // This method calculates a new name for nodes that depend on template
1194 // parameters (http://en.cppreference.com/w/cpp/language/dependent_name). The
1195 // renaming is based on crude heuristics, because such nodes are not bound to
1196 // a specific decl until template instantiation - at the point of rename, one
1197 // cannot tell whether the node will eventually resolve to a field / method /
1198 // constant / etc.
1199 //
1200 // The method returns false if no renaming should be done.
1201 // Otherwise the method returns true and sets |new_name|.
GuessNameForUnresolvedDependentNode(const TargetNode & node,clang::ASTContext & context,llvm::StringRef old_name,std::string & new_name)1202 bool GuessNameForUnresolvedDependentNode(const TargetNode& node,
1203 clang::ASTContext& context,
1204 llvm::StringRef old_name,
1205 std::string& new_name) {
1206 // |m_fieldName| -> |field_name_|.
1207 if (old_name.startswith(kBlinkFieldPrefix)) {
1208 std::string field_name = old_name.substr(strlen(kBlinkFieldPrefix));
1209 if (field_name.find('_') == std::string::npos) {
1210 new_name = CamelCaseToUnderscoreCase(field_name) + "_";
1211 return true;
1212 }
1213 }
1214
1215 // |T::myMethod(...)| -> |T::MyMethod(...)|.
1216 if ((old_name.find('_') == std::string::npos) && IsCallee(node, context) &&
1217 !IsBlacklistedMethodName(old_name)) {
1218 new_name = old_name;
1219 new_name[0] = clang::toUppercase(old_name[0]);
1220 if (ShouldPrefixFunctionName(old_name))
1221 new_name = "Get" + new_name;
1222 return true;
1223 }
1224
1225 // In the future we can consider more heuristics:
1226 // - "s_" and "g_" prefixes
1227 // - "ALL_CAPS"
1228 // - |T::myStaticField| -> |T::kMyStaticField|
1229 // (but have to be careful not to rename |value| in WTF/TypeTraits.h?)
1230 return false;
1231 }
1232 };
1233
1234 using UnresolvedDependentMemberRewriter =
1235 UnresolvedRewriterBase<clang::UnresolvedMemberExpr>;
1236
1237 using UnresolvedUsingValueDeclRewriter =
1238 UnresolvedRewriterBase<clang::UnresolvedUsingValueDecl>;
1239
1240 using DependentScopeDeclRefExprRewriter =
1241 UnresolvedRewriterBase<clang::DependentScopeDeclRefExpr>;
1242
1243 using CXXDependentScopeMemberExprRewriter =
1244 UnresolvedRewriterBase<clang::CXXDependentScopeMemberExpr>;
1245
1246 class SourceFileCallbacks : public clang::tooling::SourceFileCallbacks {
1247 public:
SourceFileCallbacks(GMockMemberRewriter * gmock_member_rewriter)1248 explicit SourceFileCallbacks(GMockMemberRewriter* gmock_member_rewriter)
1249 : gmock_member_rewriter_(gmock_member_rewriter) {
1250 assert(gmock_member_rewriter);
1251 }
1252
~SourceFileCallbacks()1253 ~SourceFileCallbacks() override {}
1254
1255 // clang::tooling::SourceFileCallbacks override:
handleBeginSource(clang::CompilerInstance & compiler,llvm::StringRef Filename)1256 bool handleBeginSource(clang::CompilerInstance& compiler,
1257 llvm::StringRef Filename) override {
1258 compiler.getPreprocessor().addPPCallbacks(
1259 gmock_member_rewriter_->CreatePreprocessorCallbacks());
1260 return true;
1261 }
1262
1263 private:
1264 GMockMemberRewriter* gmock_member_rewriter_;
1265 };
1266
1267 } // namespace
1268
1269 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
1270
main(int argc,const char * argv[])1271 int main(int argc, const char* argv[]) {
1272 // TODO(dcheng): Clang tooling should do this itself.
1273 // http://llvm.org/bugs/show_bug.cgi?id=21627
1274 llvm::InitializeNativeTarget();
1275 llvm::InitializeNativeTargetAsmParser();
1276 llvm::cl::OptionCategory category(
1277 "rewrite_to_chrome_style: convert Blink style to Chrome style.");
1278 CommonOptionsParser options(argc, argv, category);
1279 clang::tooling::ClangTool tool(options.getCompilations(),
1280 options.getSourcePathList());
1281
1282 MatchFinder match_finder;
1283 std::set<Replacement> replacements;
1284
1285 // Blink namespace matchers ========
1286 auto blink_namespace_decl =
1287 namespaceDecl(anyOf(hasName("blink"), hasName("WTF")),
1288 hasParent(translationUnitDecl()));
1289 auto protocol_namespace_decl =
1290 namespaceDecl(hasName("protocol"),
1291 hasParent(namespaceDecl(hasName("blink"),
1292 hasParent(translationUnitDecl()))));
1293
1294 // Given top-level compilation unit:
1295 // namespace WTF {
1296 // void foo() {}
1297 // }
1298 // matches |foo|.
1299 auto decl_under_blink_namespace =
1300 decl(hasAncestor(blink_namespace_decl),
1301 unless(hasAncestor(protocol_namespace_decl)));
1302
1303 // Given top-level compilation unit:
1304 // void WTF::function() {}
1305 // void WTF::Class::method() {}
1306 // matches |WTF::function| and |WTF::Class::method| decls.
1307 auto decl_has_qualifier_to_blink_namespace =
1308 declaratorDecl(has(nestedNameSpecifier(
1309 hasTopLevelPrefix(specifiesNamespace(blink_namespace_decl)))));
1310
1311 auto in_blink_namespace = decl(
1312 anyOf(decl_under_blink_namespace, decl_has_qualifier_to_blink_namespace,
1313 hasAncestor(decl_has_qualifier_to_blink_namespace)),
1314 unless(isExpansionInFileMatching(kGeneratedFileRegex)));
1315
1316 // Field, variable, and enum declarations ========
1317 // Given
1318 // int x;
1319 // struct S {
1320 // int y;
1321 // enum { VALUE };
1322 // };
1323 // matches |x|, |y|, and |VALUE|.
1324 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace));
1325 auto is_type_trait_value =
1326 varDecl(hasName("value"), hasStaticStorageDuration(), isPublic(),
1327 hasType(isConstQualified()),
1328 hasType(type(anyOf(builtinType(), enumType()))),
1329 unless(hasAncestor(recordDecl(
1330 has(cxxMethodDecl(isUserProvided(), isInstanceMethod()))))));
1331 auto var_decl_matcher =
1332 id("decl", varDecl(in_blink_namespace, unless(is_type_trait_value)));
1333 auto enum_member_decl_matcher =
1334 id("decl", enumConstantDecl(in_blink_namespace));
1335
1336 FieldDeclRewriter field_decl_rewriter(&replacements);
1337 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter);
1338
1339 VarDeclRewriter var_decl_rewriter(&replacements);
1340 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter);
1341
1342 EnumConstantDeclRewriter enum_member_decl_rewriter(&replacements);
1343 match_finder.addMatcher(enum_member_decl_matcher, &enum_member_decl_rewriter);
1344
1345 // Field, variable, and enum references ========
1346 // Given
1347 // bool x = true;
1348 // if (x) {
1349 // ...
1350 // }
1351 // matches |x| in if (x).
1352 auto member_matcher = id(
1353 "expr",
1354 memberExpr(
1355 member(field_decl_matcher),
1356 // Needed to avoid matching member references in functions (which will
1357 // be an ancestor of the member reference) synthesized by the
1358 // compiler, such as a synthesized copy constructor.
1359 // This skips explicitly defaulted functions as well, but that's OK:
1360 // there's nothing interesting to rewrite in those either.
1361 unless(hasAncestor(functionDecl(isDefaulted())))));
1362 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher)));
1363 auto enum_member_ref_matcher =
1364 id("expr", declRefExpr(to(enum_member_decl_matcher)));
1365
1366 MemberRewriter member_rewriter(&replacements);
1367 match_finder.addMatcher(member_matcher, &member_rewriter);
1368
1369 DeclRefRewriter decl_ref_rewriter(&replacements);
1370 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter);
1371
1372 EnumConstantDeclRefRewriter enum_member_ref_rewriter(&replacements);
1373 match_finder.addMatcher(enum_member_ref_matcher, &enum_member_ref_rewriter);
1374
1375 // Member references in a non-member context ========
1376 // Given
1377 // struct S {
1378 // typedef int U::*UnspecifiedBoolType;
1379 // operator UnspecifiedBoolType() { return s_ ? &U::s_ : 0; }
1380 // int s_;
1381 // };
1382 // matches |&U::s_| but not |s_|.
1383 auto member_ref_matcher = id("expr", declRefExpr(to(field_decl_matcher)));
1384
1385 FieldDeclRefRewriter member_ref_rewriter(&replacements);
1386 match_finder.addMatcher(member_ref_matcher, &member_ref_rewriter);
1387
1388 // Non-method function declarations ========
1389 // Given
1390 // void f();
1391 // struct S {
1392 // void g();
1393 // };
1394 // matches |f| but not |g|.
1395 auto function_decl_matcher = id(
1396 "decl",
1397 functionDecl(
1398 unless(anyOf(
1399 // Methods are covered by the method matchers.
1400 cxxMethodDecl(),
1401 // Out-of-line overloaded operators have special names and should
1402 // never be renamed.
1403 isOverloadedOperator(),
1404 // Must be checked after filtering out overloaded operators to
1405 // prevent asserts about the identifier not being a simple name.
1406 isBlacklistedFunction())),
1407 in_blink_namespace));
1408 FunctionDeclRewriter function_decl_rewriter(&replacements);
1409 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter);
1410
1411 // Non-method function references ========
1412 // Given
1413 // f();
1414 // void (*p)() = &f;
1415 // matches |f()| and |&f|.
1416 auto function_ref_matcher = id(
1417 "expr", declRefExpr(to(function_decl_matcher),
1418 // Ignore template substitutions.
1419 unless(hasAncestor(substNonTypeTemplateParmExpr()))));
1420 FunctionRefRewriter function_ref_rewriter(&replacements);
1421 match_finder.addMatcher(function_ref_matcher, &function_ref_rewriter);
1422
1423 // Method declarations ========
1424 // Given
1425 // struct S {
1426 // void g();
1427 // };
1428 // matches |g|.
1429 // For a method to be considered for rewrite, it must not override something
1430 // that we're not rewriting. Any methods that we would not normally consider
1431 // but that override something we are rewriting should also be rewritten. So
1432 // we use includeAllOverriddenMethods() to check these rules not just for the
1433 // method being matched but for the methods it overrides also.
1434 auto is_blink_method = includeAllOverriddenMethods(
1435 allOf(in_blink_namespace, unless(isBlacklistedMethod())));
1436 auto method_decl_matcher = id(
1437 "decl",
1438 cxxMethodDecl(
1439 unless(anyOf(
1440 // Overloaded operators have special names and should never be
1441 // renamed.
1442 isOverloadedOperator(),
1443 // Similarly, constructors, destructors, and conversion
1444 // functions should not be considered for renaming.
1445 cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())),
1446 // Check this last after excluding things, to avoid
1447 // asserts about overriding non-blink and blink for the
1448 // same method.
1449 is_blink_method));
1450 MethodDeclRewriter method_decl_rewriter(&replacements);
1451 match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter);
1452
1453 // Method references in a non-member context ========
1454 // Given
1455 // S s;
1456 // s.g();
1457 // void (S::*p)() = &S::g;
1458 // matches |&S::g| but not |s.g|.
1459 auto method_ref_matcher = id(
1460 "expr", declRefExpr(to(method_decl_matcher),
1461 // Ignore template substitutions.
1462 unless(hasAncestor(substNonTypeTemplateParmExpr()))));
1463
1464 MethodRefRewriter method_ref_rewriter(&replacements);
1465 match_finder.addMatcher(method_ref_matcher, &method_ref_rewriter);
1466
1467 // Method references in a member context ========
1468 // Given
1469 // S s;
1470 // s.g();
1471 // void (S::*p)() = &S::g;
1472 // matches |s.g| but not |&S::g|.
1473 auto method_member_matcher =
1474 id("expr", memberExpr(member(method_decl_matcher)));
1475
1476 MethodMemberRewriter method_member_rewriter(&replacements);
1477 match_finder.addMatcher(method_member_matcher, &method_member_rewriter);
1478
1479 // Initializers ========
1480 // Given
1481 // struct S {
1482 // int x;
1483 // S() : x(2) {}
1484 // };
1485 // matches each initializer in the constructor for S.
1486 auto constructor_initializer_matcher =
1487 cxxConstructorDecl(forEachConstructorInitializer(id(
1488 "initializer",
1489 cxxCtorInitializer(forAnyField(field_decl_matcher), isWritten()))));
1490
1491 ConstructorInitializerRewriter constructor_initializer_rewriter(
1492 &replacements);
1493 match_finder.addMatcher(constructor_initializer_matcher,
1494 &constructor_initializer_rewriter);
1495
1496 // Unresolved lookup expressions ========
1497 // Given
1498 // template<typename T> void F(T) { }
1499 // template<void G(T)> H(T) { }
1500 // H<F<int>>(...);
1501 // matches |F| in |H<F<int>>|.
1502 //
1503 // UnresolvedLookupExprs are similar to DeclRefExprs that reference a
1504 // FunctionDecl, but are used when a candidate FunctionDecl can't be selected.
1505 // This commonly happens inside uninstantiated template definitions for one of
1506 // two reasons:
1507 //
1508 // 1. If the candidate declaration is a dependent FunctionTemplateDecl, the
1509 // actual overload can't be selected until template instantiation time.
1510 // 2. Alternatively, there might be multiple declarations in the candidate set
1511 // if the candidate function has overloads. If any of the function
1512 // arguments has a dependent type, then the actual overload can't be
1513 // selected until instantiation time either.
1514 //
1515 // Another instance where UnresolvedLookupExprs can appear is in a template
1516 // argument list, like the provided example.
1517 auto function_template_decl_matcher =
1518 id("decl", functionTemplateDecl(templatedDecl(function_decl_matcher)));
1519 auto method_template_decl_matcher =
1520 id("decl", functionTemplateDecl(templatedDecl(method_decl_matcher)));
1521 auto unresolved_lookup_matcher = expr(id(
1522 "expr",
1523 unresolvedLookupExpr(
1524 // In order to automatically rename an unresolved lookup, the lookup
1525 // candidates must either all be Blink functions/function templates or
1526 // all be Blink methods/method templates. Otherwise, we might end up
1527 // in a situation where the naming could change depending on the
1528 // selected candidate.
1529 anyOf(allOverloadsMatch(anyOf(function_decl_matcher,
1530 function_template_decl_matcher)),
1531 // Note: this matches references to methods in a non-member
1532 // context, e.g. Template<&Class::Method>. This and the
1533 // UnresolvedMemberExpr matcher below are analogous to how the
1534 // rewriter has both a MemberRefRewriter matcher to rewrite
1535 // &T::method and a MethodMemberRewriter matcher to rewriter
1536 // t.method().
1537 allOverloadsMatch(anyOf(method_decl_matcher,
1538 method_template_decl_matcher))))));
1539 UnresolvedLookupRewriter unresolved_lookup_rewriter(&replacements);
1540 match_finder.addMatcher(unresolved_lookup_matcher,
1541 &unresolved_lookup_rewriter);
1542
1543 // Unresolved member expressions (for non-dependent fields / methods) ========
1544 // Similar to unresolved lookup expressions, but for methods in a member
1545 // context, e.g. var_with_templated_type.Method().
1546 auto unresolved_member_matcher = expr(id(
1547 "expr",
1548 unresolvedMemberExpr(
1549 // Similar to UnresolvedLookupExprs, all the candidate methods must be
1550 // Blink methods/method templates.
1551 allOverloadsMatch(
1552 anyOf(method_decl_matcher, method_template_decl_matcher)))));
1553 UnresolvedMemberRewriter unresolved_member_rewriter(&replacements);
1554 match_finder.addMatcher(unresolved_member_matcher,
1555 &unresolved_member_rewriter);
1556
1557 // Unresolved using value decls ========
1558 // Example:
1559 // template <typename T>
1560 // class BaseClass {
1561 // public:
1562 // unsigned long m_size;
1563 // };
1564 // template <typename T>
1565 // class DerivedClass : protected BaseClass<T> {
1566 // private:
1567 // using Base = BaseClass<T>;
1568 // using Base::m_size; // <- |m_size| here is matched by
1569 // void method() { // |unresolved_using_value_decl_matcher|.
1570 // m_size = 123; // <- |m_size| here is matched by
1571 // } // |unresolved_dependent_using_matcher|.
1572 // };
1573 auto unresolved_dependent_using_matcher =
1574 expr(id("expr", unresolvedMemberExpr(allOverloadsMatch(allOf(
1575 in_blink_namespace, unresolvedUsingValueDecl())))));
1576 UnresolvedDependentMemberRewriter unresolved_dependent_member_rewriter(
1577 &replacements);
1578 match_finder.addMatcher(unresolved_dependent_using_matcher,
1579 &unresolved_dependent_member_rewriter);
1580 auto unresolved_using_value_decl_matcher =
1581 decl(id("decl", unresolvedUsingValueDecl(in_blink_namespace)));
1582 UnresolvedUsingValueDeclRewriter unresolved_using_value_decl_rewriter(
1583 &replacements);
1584 match_finder.addMatcher(unresolved_using_value_decl_matcher,
1585 &unresolved_using_value_decl_rewriter);
1586
1587 // Using declarations ========
1588 // Given
1589 // using blink::X;
1590 // matches |using blink::X|.
1591 auto using_decl_matcher = id(
1592 "decl", usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(anyOf(
1593 var_decl_matcher, field_decl_matcher, function_decl_matcher,
1594 method_decl_matcher, function_template_decl_matcher,
1595 method_template_decl_matcher, enum_member_decl_matcher)))));
1596 UsingDeclRewriter using_decl_rewriter(&replacements);
1597 match_finder.addMatcher(using_decl_matcher, &using_decl_rewriter);
1598
1599 // Matches any QualType that refers to a blink type:
1600 // - const blink::Foo&
1601 // - blink::Foo*
1602 // - blink::Foo<T>
1603 auto blink_qual_type_base_matcher = hasBaseType(hasUnqualifiedDesugaredType(
1604 anyOf(enumType(hasDeclaration(in_blink_namespace)),
1605 injectedClassNameType(hasDeclaration(in_blink_namespace)),
1606 recordType(hasDeclaration(in_blink_namespace)),
1607 templateSpecializationType(hasDeclaration(in_blink_namespace)),
1608 templateTypeParmType(hasDeclaration(in_blink_namespace)))));
1609 auto blink_qual_type_matcher = qualType(anyOf(
1610 blink_qual_type_base_matcher, pointsTo(blink_qual_type_base_matcher),
1611 references(blink_qual_type_base_matcher)));
1612
1613 // Template-dependent decl lookup ========
1614 // Given
1615 // template <typename T> void f() { T::foo(); }
1616 // matches |T::foo|.
1617 auto dependent_scope_decl_ref_expr_matcher =
1618 expr(id("expr", dependentScopeDeclRefExpr(has(nestedNameSpecifier(
1619 specifiesType(blink_qual_type_matcher))))));
1620 DependentScopeDeclRefExprRewriter dependent_scope_decl_ref_expr_rewriter(
1621 &replacements);
1622 match_finder.addMatcher(dependent_scope_decl_ref_expr_matcher,
1623 &dependent_scope_decl_ref_expr_rewriter);
1624
1625 // Template-dependent member lookup ========
1626 // Given
1627 // template <typename T>
1628 // class Foo {
1629 // void f() { T::foo(); }
1630 // void g(T x) { x.bar(); }
1631 // };
1632 // matches |T::foo| and |x.bar|.
1633 auto cxx_dependent_scope_member_expr_matcher =
1634 expr(id("expr", cxxDependentScopeMemberExpr(
1635 hasMemberFromType(blink_qual_type_matcher))));
1636 CXXDependentScopeMemberExprRewriter cxx_dependent_scope_member_expr_rewriter(
1637 &replacements);
1638 match_finder.addMatcher(cxx_dependent_scope_member_expr_matcher,
1639 &cxx_dependent_scope_member_expr_rewriter);
1640
1641 // GMock calls lookup ========
1642 // Given
1643 // EXPECT_CALL(obj, myMethod(...))
1644 // will match obj.gmock_myMethod(...) call generated by the macro
1645 // (but only if it mocks a Blink method).
1646 auto gmock_member_matcher =
1647 id("expr", memberExpr(hasDeclaration(
1648 decl(cxxMethodDecl(mocksMethod(method_decl_matcher))))));
1649 GMockMemberRewriter gmock_member_rewriter(&replacements);
1650 match_finder.addMatcher(gmock_member_matcher, &gmock_member_rewriter);
1651
1652 // Prepare and run the tool.
1653 SourceFileCallbacks source_file_callbacks(&gmock_member_rewriter);
1654 std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
1655 clang::tooling::newFrontendActionFactory(&match_finder,
1656 &source_file_callbacks);
1657 int result = tool.run(factory.get());
1658 if (result != 0)
1659 return result;
1660
1661 // Supplemental data for the Blink rename rebase helper.
1662 // TODO(dcheng): There's a lot of match rewriters missing from this list.
1663 llvm::outs() << "==== BEGIN TRACKED EDITS ====\n";
1664 field_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs());
1665 var_decl_rewriter.edit_tracker().SerializeTo("var", llvm::outs());
1666 enum_member_decl_rewriter.edit_tracker().SerializeTo("enu", llvm::outs());
1667 function_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs());
1668 method_decl_rewriter.edit_tracker().SerializeTo("fun", llvm::outs());
1669 llvm::outs() << "==== END TRACKED EDITS ====\n";
1670
1671 // Serialization format is documented in tools/clang/scripts/run_tool.py
1672 llvm::outs() << "==== BEGIN EDITS ====\n";
1673 for (const auto& r : replacements) {
1674 std::string replacement_text = r.getReplacementText().str();
1675 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
1676 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset()
1677 << ":::" << r.getLength() << ":::" << replacement_text << "\n";
1678 }
1679 llvm::outs() << "==== END EDITS ====\n";
1680
1681 return 0;
1682 }
1683