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 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> 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 81 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { 82 return Node.isOverloadedOperator(); 83 } 84 85 AST_MATCHER(clang::CXXMethodDecl, isInstanceMethod) { 86 return Node.isInstance(); 87 } 88 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 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). 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: 137 explicit MethodBlocklist(const std::string& filepath) { 138 if (!filepath.empty()) 139 ParseInputFile(filepath); 140 } 141 142 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> 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 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| 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. 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. 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 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> 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 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. 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>|. 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 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 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 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 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 440 bool IsBlacklistedMethodName(llvm::StringRef name) { 441 return IsBlacklistedFunctionName(name) || 442 IsBlacklistedInstanceMethodName(name); 443 } 444 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 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 478 AST_MATCHER(clang::FunctionDecl, isBlacklistedFunction) { 479 return IsBlacklistedFunction(Node); 480 } 481 482 AST_MATCHER(clang::CXXMethodDecl, isBlacklistedMethod) { 483 return IsBlacklistedMethod(Node); 484 } 485 486 bool IsKnownTraitName(clang::StringRef name) { 487 // This set of names is globally a type trait throughout chromium. 488 return name == "safeToCompareToEmptyOrDeleted"; 489 } 490 491 AST_MATCHER(clang::VarDecl, isKnownTraitName) { 492 return Node.getDeclName().isIdentifier() && IsKnownTraitName(Node.getName()); 493 } 494 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. 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 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 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 666 AST_MATCHER_P(clang::QualType, hasString, std::string, ExpectedString) { 667 return ExpectedString == Node.getAsString(); 668 } 669 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 793 AST_MATCHER(clang::FunctionDecl, shouldPrefixFunctionName) { 794 return Node.getDeclName().isIdentifier() && 795 ShouldPrefixFunctionName(Node.getName().str()); 796 } 797 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 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 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 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 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 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 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> { 993 static clang::SourceLocation GetLoc(const clang::NamedDecl& decl) { 994 return decl.getLocation(); 995 } 996 static const char* GetName() { return "decl"; } 997 static const char* GetType() { return "NamedDecl"; } 998 }; 999 1000 template <> 1001 struct TargetNodeTraits<clang::MemberExpr> { 1002 static clang::SourceLocation GetLoc(const clang::MemberExpr& expr) { 1003 return expr.getMemberLoc(); 1004 } 1005 static const char* GetName() { return "expr"; } 1006 static const char* GetType() { return "MemberExpr"; } 1007 }; 1008 1009 template <> 1010 struct TargetNodeTraits<clang::DeclRefExpr> { 1011 static clang::SourceLocation GetLoc(const clang::DeclRefExpr& expr) { 1012 return expr.getLocation(); 1013 } 1014 static const char* GetName() { return "expr"; } 1015 static const char* GetType() { return "DeclRefExpr"; } 1016 }; 1017 1018 template <> 1019 struct TargetNodeTraits<clang::DependentScopeDeclRefExpr> { 1020 static clang::SourceLocation GetLoc( 1021 const clang::DependentScopeDeclRefExpr& expr) { 1022 return expr.getLocation(); 1023 } 1024 static const char* GetName() { return "expr"; } 1025 }; 1026 1027 template <> 1028 struct TargetNodeTraits<clang::CXXDependentScopeMemberExpr> { 1029 static clang::SourceLocation GetLoc( 1030 const clang::CXXDependentScopeMemberExpr& expr) { 1031 return expr.getMemberLoc(); 1032 } 1033 static const char* GetName() { return "expr"; } 1034 }; 1035 1036 template <> 1037 struct TargetNodeTraits<clang::CXXCtorInitializer> { 1038 static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) { 1039 assert(init.isWritten()); 1040 return init.getSourceLocation(); 1041 } 1042 static const char* GetName() { return "initializer"; } 1043 static const char* GetType() { return "CXXCtorInitializer"; } 1044 }; 1045 1046 template <> 1047 struct TargetNodeTraits<clang::UnresolvedLookupExpr> { 1048 static clang::SourceLocation GetLoc(const clang::UnresolvedLookupExpr& expr) { 1049 return expr.getNameLoc(); 1050 } 1051 static const char* GetName() { return "expr"; } 1052 static const char* GetType() { return "UnresolvedLookupExpr"; } 1053 }; 1054 1055 template <> 1056 struct TargetNodeTraits<clang::UnresolvedMemberExpr> { 1057 static clang::SourceLocation GetLoc(const clang::UnresolvedMemberExpr& expr) { 1058 return expr.getMemberLoc(); 1059 } 1060 static const char* GetName() { return "expr"; } 1061 static const char* GetType() { return "UnresolvedMemberExpr"; } 1062 }; 1063 1064 template <> 1065 struct TargetNodeTraits<clang::UnresolvedUsingValueDecl> { 1066 static clang::SourceLocation GetLoc( 1067 const clang::UnresolvedUsingValueDecl& decl) { 1068 return decl.getNameInfo().getLoc(); 1069 } 1070 static const char* GetName() { return "decl"; } 1071 static const char* GetType() { return "UnresolvedUsingValueDecl"; } 1072 }; 1073 1074 template <typename TargetNode> 1075 class RewriterBase : public MatchFinder::MatchCallback { 1076 public: 1077 explicit RewriterBase(std::set<Replacement>* replacements, 1078 RenameCategory category) 1079 : replacements_(replacements), edit_tracker_(category) {} 1080 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 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 1150 virtual clang::SourceLocation GetTargetLoc( 1151 const MatchFinder::MatchResult& result) { 1152 return TargetNodeTraits<TargetNode>::GetLoc(GetTargetNode(result)); 1153 } 1154 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 1173 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 <> 1183 RenameCategory GetCategory<clang::FieldDecl>() { 1184 return RenameCategory::kField; 1185 } 1186 template <> 1187 RenameCategory GetCategory<clang::VarDecl>() { 1188 return RenameCategory::kVariable; 1189 } 1190 template <> 1191 RenameCategory GetCategory<clang::FunctionDecl>() { 1192 return RenameCategory::kFunction; 1193 } 1194 template <> 1195 RenameCategory GetCategory<clang::CXXMethodDecl>() { 1196 return RenameCategory::kFunction; 1197 } 1198 template <> 1199 RenameCategory GetCategory<clang::EnumConstantDecl>() { 1200 return RenameCategory::kEnumValue; 1201 } 1202 template <> 1203 RenameCategory GetCategory<clang::NamedDecl>() { 1204 return RenameCategory::kUnresolved; 1205 } 1206 template <> 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 1216 explicit DeclRewriterBase(std::set<Replacement>* replacements) 1217 : Base(replacements, GetCategory<DeclNode>()) {} 1218 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 1285 explicit GMockMemberRewriter(std::set<Replacement>* replacements) 1286 : Base(replacements) {} 1287 1288 std::unique_ptr<clang::PPCallbacks> CreatePreprocessorCallbacks() { 1289 return llvm::make_unique<GMockMemberRewriter::PPCallbacks>(this); 1290 } 1291 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 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: 1324 explicit PPCallbacks(GMockMemberRewriter* rewriter) : rewriter_(rewriter) {} 1325 ~PPCallbacks() override {} 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 1353 clang::DeclarationName GetUnresolvedName( 1354 const clang::UnresolvedMemberExpr& expr) { 1355 return expr.getMemberName(); 1356 } 1357 1358 clang::DeclarationName GetUnresolvedName( 1359 const clang::DependentScopeDeclRefExpr& expr) { 1360 return expr.getDeclName(); 1361 } 1362 1363 clang::DeclarationName GetUnresolvedName( 1364 const clang::CXXDependentScopeMemberExpr& expr) { 1365 return expr.getMember(); 1366 } 1367 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). 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). 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 1403 explicit UnresolvedRewriterBase(std::set<Replacement>* replacements) 1404 : RewriterBase<TargetNode>(replacements, RenameCategory::kUnresolved) {} 1405 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|. 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: 1492 explicit SourceFileCallbacks(GMockMemberRewriter* gmock_member_rewriter) 1493 : gmock_member_rewriter_(gmock_member_rewriter) { 1494 assert(gmock_member_rewriter); 1495 } 1496 1497 ~SourceFileCallbacks() override {} 1498 1499 // clang::tooling::SourceFileCallbacks override: 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 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