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