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 <fstream> 18 #include <memory> 19 #include <string> 20 #include <unordered_map> 21 22 #include "clang/AST/ASTContext.h" 23 #include "clang/ASTMatchers/ASTMatchFinder.h" 24 #include "clang/ASTMatchers/ASTMatchers.h" 25 #include "clang/ASTMatchers/ASTMatchersMacros.h" 26 #include "clang/Basic/CharInfo.h" 27 #include "clang/Basic/SourceManager.h" 28 #include "clang/Frontend/FrontendActions.h" 29 #include "clang/Lex/Lexer.h" 30 #include "clang/Tooling/CommonOptionsParser.h" 31 #include "clang/Tooling/Refactoring.h" 32 #include "clang/Tooling/Tooling.h" 33 #include "llvm/Support/CommandLine.h" 34 #include "llvm/Support/TargetSelect.h" 35 36 #if defined(_WIN32) 37 #include <windows.h> 38 #else 39 #include <sys/file.h> 40 #include <unistd.h> 41 #endif 42 43 using namespace clang::ast_matchers; 44 using clang::tooling::CommonOptionsParser; 45 using clang::tooling::Replacement; 46 using llvm::StringRef; 47 48 namespace { 49 50 const char kBlinkFieldPrefix[] = "m_"; 51 const char kBlinkStaticMemberPrefix[] = "s_"; 52 const char kGeneratedFileRegex[] = "^gen/|/gen/"; 53 54 const clang::ast_matchers::internal:: 55 VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr> 56 unresolvedMemberExpr; 57 58 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { 59 return Node.isOverloadedOperator(); 60 } 61 62 AST_MATCHER(clang::CXXMethodDecl, isInstanceMethod) { 63 return Node.isInstance(); 64 } 65 66 AST_MATCHER_P(clang::FunctionTemplateDecl, 67 templatedDecl, 68 clang::ast_matchers::internal::Matcher<clang::FunctionDecl>, 69 InnerMatcher) { 70 return InnerMatcher.matches(*Node.getTemplatedDecl(), Finder, Builder); 71 } 72 73 // If |InnerMatcher| matches |top|, then the returned matcher will match: 74 // - |top::function| 75 // - |top::Class::method| 76 // - |top::internal::Class::method| 77 AST_MATCHER_P( 78 clang::NestedNameSpecifier, 79 hasTopLevelPrefix, 80 clang::ast_matchers::internal::Matcher<clang::NestedNameSpecifier>, 81 InnerMatcher) { 82 const clang::NestedNameSpecifier* NodeToMatch = &Node; 83 while (NodeToMatch->getPrefix()) 84 NodeToMatch = NodeToMatch->getPrefix(); 85 return InnerMatcher.matches(*NodeToMatch, Finder, Builder); 86 } 87 88 // This will narrow CXXCtorInitializers down for both FieldDecls and 89 // IndirectFieldDecls (ie. anonymous unions and such). In both cases 90 // getAnyMember() will return a FieldDecl which we can match against. 91 AST_MATCHER_P(clang::CXXCtorInitializer, 92 forAnyField, 93 clang::ast_matchers::internal::Matcher<clang::FieldDecl>, 94 InnerMatcher) { 95 const clang::FieldDecl* NodeAsDecl = Node.getAnyMember(); 96 return (NodeAsDecl != nullptr && 97 InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); 98 } 99 100 // Matches if all the overloads in the lookup set match the provided matcher. 101 AST_MATCHER_P(clang::OverloadExpr, 102 allOverloadsMatch, 103 clang::ast_matchers::internal::Matcher<clang::NamedDecl>, 104 InnerMatcher) { 105 if (Node.getNumDecls() == 0) 106 return false; 107 108 for (clang::NamedDecl* decl : Node.decls()) { 109 if (!InnerMatcher.matches(*decl, Finder, Builder)) 110 return false; 111 } 112 return true; 113 } 114 115 template <typename T> 116 bool MatchAllOverriddenMethods( 117 const clang::CXXMethodDecl& decl, 118 T&& inner_matcher, 119 clang::ast_matchers::internal::ASTMatchFinder* finder, 120 clang::ast_matchers::internal::BoundNodesTreeBuilder* builder) { 121 bool override_matches = false; 122 bool override_not_matches = false; 123 124 for (auto it = decl.begin_overridden_methods(); 125 it != decl.end_overridden_methods(); ++it) { 126 if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder)) 127 override_matches = true; 128 else 129 override_not_matches = true; 130 } 131 132 // If this fires we have a class overriding a method that matches, and a 133 // method that does not match the inner matcher. In that case we will match 134 // one ancestor method but not the other. If we rename one of the and not the 135 // other it will break what this class overrides, disconnecting it from the 136 // one we did not rename which creates a behaviour change. So assert and 137 // demand the user to fix the code first (or add the method to our 138 // blacklist T_T). 139 if (override_matches || override_not_matches) 140 assert(override_matches != override_not_matches); 141 142 // If the method overrides something that doesn't match, so the method itself 143 // doesn't match. 144 if (override_not_matches) 145 return false; 146 // If the method overrides something that matches, so the method ifself 147 // matches. 148 if (override_matches) 149 return true; 150 151 return inner_matcher.matches(decl, finder, builder); 152 } 153 154 AST_MATCHER_P(clang::CXXMethodDecl, 155 includeAllOverriddenMethods, 156 clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>, 157 InnerMatcher) { 158 return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder); 159 } 160 161 bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl, 162 const char* class_name) { 163 if (decl.getParent()->getQualifiedNameAsString() == class_name) 164 return true; 165 for (auto it = decl.begin_overridden_methods(); 166 it != decl.end_overridden_methods(); ++it) { 167 if (IsMethodOverrideOf(**it, class_name)) 168 return true; 169 } 170 return false; 171 } 172 173 bool IsBlacklistedFunction(const clang::FunctionDecl& decl) { 174 // swap() functions should match the signature of std::swap for ADL tricks. 175 return decl.getName() == "swap"; 176 } 177 178 bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) { 179 if (decl.isStatic()) 180 return false; 181 182 clang::StringRef name = decl.getName(); 183 184 // These methods should never be renamed. 185 static const char* kBlacklistMethods[] = {"trace", "traceImpl", "lock", 186 "unlock", "try_lock"}; 187 for (const auto& b : kBlacklistMethods) { 188 if (name == b) 189 return true; 190 } 191 192 // Iterator methods shouldn't be renamed to work with stl and range-for 193 // loops. 194 std::string ret_type = decl.getReturnType().getAsString(); 195 if (ret_type.find("iterator") != std::string::npos || 196 ret_type.find("Iterator") != std::string::npos) { 197 static const char* kIteratorBlacklist[] = {"begin", "end", "rbegin", 198 "rend"}; 199 for (const auto& b : kIteratorBlacklist) { 200 if (name == b) 201 return true; 202 } 203 } 204 205 // Subclasses of InspectorAgent will subclass "disable()" from both blink and 206 // from gen/, which is problematic, but DevTools folks don't want to rename 207 // it or split this up. So don't rename it at all. 208 if (name.equals("disable") && 209 IsMethodOverrideOf(decl, "blink::InspectorAgent")) 210 return true; 211 212 return false; 213 } 214 215 AST_MATCHER(clang::FunctionDecl, isBlacklistedFunction) { 216 return IsBlacklistedFunction(Node); 217 } 218 219 AST_MATCHER(clang::CXXMethodDecl, isBlacklistedMethod) { 220 return IsBlacklistedMethod(Node); 221 } 222 223 // Helper to convert from a camelCaseName to camel_case_name. It uses some 224 // heuristics to try to handle acronyms in camel case names correctly. 225 std::string CamelCaseToUnderscoreCase(StringRef input) { 226 std::string output; 227 bool needs_underscore = false; 228 bool was_lowercase = false; 229 bool was_uppercase = false; 230 bool first_char = true; 231 // Iterate in reverse to minimize the amount of backtracking. 232 for (const unsigned char* i = input.bytes_end() - 1; i >= input.bytes_begin(); 233 --i) { 234 char c = *i; 235 bool is_lowercase = clang::isLowercase(c); 236 bool is_uppercase = clang::isUppercase(c); 237 c = clang::toLowercase(c); 238 // Transitioning from upper to lower case requires an underscore. This is 239 // needed to handle names with acronyms, e.g. handledHTTPRequest needs a '_' 240 // in 'dH'. This is a complement to the non-acronym case further down. 241 if (was_uppercase && is_lowercase) 242 needs_underscore = true; 243 if (needs_underscore) { 244 output += '_'; 245 needs_underscore = false; 246 } 247 output += c; 248 // Handles the non-acronym case: transitioning from lower to upper case 249 // requires an underscore when emitting the next character, e.g. didLoad 250 // needs a '_' in 'dL'. 251 if (!first_char && was_lowercase && is_uppercase) 252 needs_underscore = true; 253 was_lowercase = is_lowercase; 254 was_uppercase = is_uppercase; 255 first_char = false; 256 } 257 std::reverse(output.begin(), output.end()); 258 return output; 259 } 260 261 bool IsProbablyConst(const clang::VarDecl& decl, 262 const clang::ASTContext& context) { 263 clang::QualType type = decl.getType(); 264 if (!type.isConstQualified()) 265 return false; 266 267 if (type.isVolatileQualified()) 268 return false; 269 270 // http://google.github.io/styleguide/cppguide.html#Constant_Names 271 // Static variables that are const-qualified should use kConstantStyle naming. 272 if (decl.getStorageDuration() == clang::SD_Static) 273 return true; 274 275 const clang::Expr* initializer = decl.getInit(); 276 if (!initializer) 277 return false; 278 279 // If the expression is dependent on a template input, then we are not 280 // sure if it can be compile-time generated as calling isEvaluatable() is 281 // not valid on |initializer|. 282 // TODO(crbug.com/581218): We could probably look at each compiled 283 // instantiation of the template and see if they are all compile-time 284 // isEvaluable(). 285 if (initializer->isInstantiationDependent()) 286 return false; 287 288 // If the expression can be evaluated at compile time, then it should have a 289 // kFoo style name. Otherwise, not. 290 return initializer->isEvaluatable(context); 291 } 292 293 AST_MATCHER_P(clang::QualType, hasString, std::string, ExpectedString) { 294 return ExpectedString == Node.getAsString(); 295 } 296 297 bool GetNameForDecl(const clang::FunctionDecl& decl, 298 clang::ASTContext& context, 299 std::string& name) { 300 name = decl.getName().str(); 301 name[0] = clang::toUppercase(name[0]); 302 303 // Given 304 // class Foo {}; 305 // using Bar = Foo; 306 // Bar f1(); // <- |Bar| would be matched by hasString("Bar") below. 307 // Bar f2(); // <- |Bar| would be matched by hasName("Foo") below. 308 // |type_with_same_name_as_function| matcher matches Bar and Foo return types. 309 auto type_with_same_name_as_function = qualType(anyOf( 310 hasString(name), // hasString matches the type as spelled (Bar above). 311 hasDeclaration(namedDecl(hasName(name))))); // hasDeclaration matches 312 // resolved type (Foo above). 313 // |type_containing_same_name_as_function| matcher will match all of the 314 // return types below: 315 // - Foo foo() // Direct application of |type_with_same_name_as_function|. 316 // - Foo* foo() // |hasDescendant| traverses references/pointers. 317 // - RefPtr<Foo> foo() // |hasDescendant| traverses template arguments. 318 auto type_containing_same_name_as_function = 319 qualType(anyOf(type_with_same_name_as_function, 320 hasDescendant(type_with_same_name_as_function))); 321 // https://crbug.com/582312: Prepend "Get" if method name conflicts with 322 // return type. 323 auto conflict_matcher = 324 functionDecl(returns(type_containing_same_name_as_function)); 325 if (!match(conflict_matcher, decl, context).empty()) 326 name = "Get" + name; 327 328 return true; 329 } 330 331 bool GetNameForDecl(const clang::EnumConstantDecl& decl, 332 clang::ASTContext& context, 333 std::string& name) { 334 StringRef original_name = decl.getName(); 335 336 // If it's already correct leave it alone. 337 if (original_name.size() >= 2 && original_name[0] == 'k' && 338 clang::isUppercase(original_name[1])) 339 return false; 340 341 bool is_shouty = true; 342 for (char c : original_name) { 343 if (!clang::isUppercase(c) && !clang::isDigit(c) && c != '_') { 344 is_shouty = false; 345 break; 346 } 347 } 348 349 if (is_shouty) 350 return false; 351 352 name = 'k'; // k prefix on enum values. 353 name += original_name; 354 name[1] = clang::toUppercase(name[1]); 355 return true; 356 } 357 358 bool GetNameForDecl(const clang::FieldDecl& decl, 359 clang::ASTContext& context, 360 std::string& name) { 361 StringRef original_name = decl.getName(); 362 bool member_prefix = original_name.startswith(kBlinkFieldPrefix); 363 364 StringRef rename_part = !member_prefix 365 ? original_name 366 : original_name.substr(strlen(kBlinkFieldPrefix)); 367 name = CamelCaseToUnderscoreCase(rename_part); 368 369 // Assume that prefix of m_ was intentional and always replace it with a 370 // suffix _. 371 if (member_prefix && name.back() != '_') 372 name += '_'; 373 374 return true; 375 } 376 377 bool GetNameForDecl(const clang::VarDecl& decl, 378 clang::ASTContext& context, 379 std::string& name) { 380 StringRef original_name = decl.getName(); 381 382 // Nothing to do for unnamed parameters. 383 if (clang::isa<clang::ParmVarDecl>(decl)) { 384 if (original_name.empty()) 385 return false; 386 387 // Check if |decl| and |decl.getLocation| are in sync. We need to skip 388 // out-of-sync ParmVarDecls to avoid renaming buggy ParmVarDecls that 389 // 1) have decl.getLocation() pointing at a parameter declaration without a 390 // name, but 2) have decl.getName() retained from a template specialization 391 // of a method. See also: https://llvm.org/bugs/show_bug.cgi?id=29145 392 clang::SourceLocation loc = 393 context.getSourceManager().getSpellingLoc(decl.getLocation()); 394 auto parents = context.getParents(decl); 395 bool is_child_location_within_parent_source_range = std::all_of( 396 parents.begin(), parents.end(), 397 [&loc](const clang::ast_type_traits::DynTypedNode& parent) { 398 clang::SourceLocation begin = parent.getSourceRange().getBegin(); 399 clang::SourceLocation end = parent.getSourceRange().getEnd(); 400 return (begin < loc) && (loc < end); 401 }); 402 if (!is_child_location_within_parent_source_range) 403 return false; 404 } 405 406 // static class members match against VarDecls. Blink style dictates that 407 // these should be prefixed with `s_`, so strip that off. Also check for `m_` 408 // and strip that off too, for code that accidentally uses the wrong prefix. 409 if (original_name.startswith(kBlinkStaticMemberPrefix)) 410 original_name = original_name.substr(strlen(kBlinkStaticMemberPrefix)); 411 else if (original_name.startswith(kBlinkFieldPrefix)) 412 original_name = original_name.substr(strlen(kBlinkFieldPrefix)); 413 414 bool is_const = IsProbablyConst(decl, context); 415 if (is_const) { 416 // Don't try to rename constants that already conform to Chrome style. 417 if (original_name.size() >= 2 && original_name[0] == 'k' && 418 clang::isUppercase(original_name[1])) 419 return false; 420 421 name = 'k'; 422 name.append(original_name.data(), original_name.size()); 423 name[1] = clang::toUppercase(name[1]); 424 } else { 425 name = CamelCaseToUnderscoreCase(original_name); 426 427 // Non-const variables with static storage duration at namespace scope are 428 // prefixed with `g_' to reduce the likelihood of a naming collision. 429 const clang::DeclContext* decl_context = decl.getDeclContext(); 430 if (name.find("g_") != 0 && decl.hasGlobalStorage() && 431 decl_context->isNamespace()) 432 name.insert(0, "g_"); 433 } 434 435 // Static members end with _ just like other members, but constants should 436 // not. 437 if (!is_const && decl.isStaticDataMember()) { 438 name += '_'; 439 } 440 441 return true; 442 } 443 444 bool GetNameForDecl(const clang::FunctionTemplateDecl& decl, 445 clang::ASTContext& context, 446 std::string& name) { 447 clang::FunctionDecl* templated_function = decl.getTemplatedDecl(); 448 return GetNameForDecl(*templated_function, context, name); 449 } 450 451 bool GetNameForDecl(const clang::NamedDecl& decl, 452 clang::ASTContext& context, 453 std::string& name) { 454 if (auto* function = clang::dyn_cast<clang::FunctionDecl>(&decl)) 455 return GetNameForDecl(*function, context, name); 456 if (auto* var = clang::dyn_cast<clang::VarDecl>(&decl)) 457 return GetNameForDecl(*var, context, name); 458 if (auto* field = clang::dyn_cast<clang::FieldDecl>(&decl)) 459 return GetNameForDecl(*field, context, name); 460 if (auto* function_template = 461 clang::dyn_cast<clang::FunctionTemplateDecl>(&decl)) 462 return GetNameForDecl(*function_template, context, name); 463 if (auto* enumc = clang::dyn_cast<clang::EnumConstantDecl>(&decl)) 464 return GetNameForDecl(*enumc, context, name); 465 466 return false; 467 } 468 469 bool GetNameForDecl(const clang::UsingDecl& decl, 470 clang::ASTContext& context, 471 std::string& name) { 472 assert(decl.shadow_size() > 0); 473 474 // If a using declaration's targeted declaration is a set of overloaded 475 // functions, it can introduce multiple shadowed declarations. Just using the 476 // first one is OK, since overloaded functions have the same name, by 477 // definition. 478 return GetNameForDecl(*decl.shadow_begin()->getTargetDecl(), context, name); 479 } 480 481 template <typename Type> 482 struct TargetNodeTraits; 483 484 template <> 485 struct TargetNodeTraits<clang::NamedDecl> { 486 static clang::SourceLocation GetLoc(const clang::NamedDecl& decl) { 487 return decl.getLocation(); 488 } 489 static const char* GetName() { return "decl"; } 490 static const char* GetType() { return "NamedDecl"; } 491 }; 492 493 template <> 494 struct TargetNodeTraits<clang::MemberExpr> { 495 static clang::SourceLocation GetLoc(const clang::MemberExpr& expr) { 496 return expr.getMemberLoc(); 497 } 498 static const char* GetName() { return "expr"; } 499 static const char* GetType() { return "MemberExpr"; } 500 }; 501 502 template <> 503 struct TargetNodeTraits<clang::DeclRefExpr> { 504 static clang::SourceLocation GetLoc(const clang::DeclRefExpr& expr) { 505 return expr.getLocation(); 506 } 507 static const char* GetName() { return "expr"; } 508 static const char* GetType() { return "DeclRefExpr"; } 509 }; 510 511 template <> 512 struct TargetNodeTraits<clang::CXXCtorInitializer> { 513 static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) { 514 assert(init.isWritten()); 515 return init.getSourceLocation(); 516 } 517 static const char* GetName() { return "initializer"; } 518 static const char* GetType() { return "CXXCtorInitializer"; } 519 }; 520 521 template <> 522 struct TargetNodeTraits<clang::UnresolvedLookupExpr> { 523 static clang::SourceLocation GetLoc(const clang::UnresolvedLookupExpr& expr) { 524 return expr.getNameLoc(); 525 } 526 static const char* GetName() { return "expr"; } 527 static const char* GetType() { return "UnresolvedLookupExpr"; } 528 }; 529 530 template <> 531 struct TargetNodeTraits<clang::UnresolvedMemberExpr> { 532 static clang::SourceLocation GetLoc(const clang::UnresolvedMemberExpr& expr) { 533 return expr.getMemberLoc(); 534 } 535 static const char* GetName() { return "expr"; } 536 static const char* GetType() { return "UnresolvedMemberExpr"; } 537 }; 538 539 template <typename DeclNode, typename TargetNode> 540 class RewriterBase : public MatchFinder::MatchCallback { 541 public: 542 explicit RewriterBase(std::set<Replacement>* replacements) 543 : replacements_(replacements) {} 544 545 void run(const MatchFinder::MatchResult& result) override { 546 const DeclNode* decl = result.Nodes.getNodeAs<DeclNode>("decl"); 547 // If false, there's no name to be renamed. 548 if (!decl->getIdentifier()) 549 return; 550 clang::SourceLocation decl_loc = 551 TargetNodeTraits<clang::NamedDecl>::GetLoc(*decl); 552 if (decl_loc.isMacroID()) { 553 // Get the location of the spelling of the declaration. If token pasting 554 // was used this will be in "scratch space" and we don't know how to get 555 // from there back to/ the actual macro with the foo##bar text. So just 556 // don't replace in that case. 557 clang::SourceLocation spell = 558 result.SourceManager->getSpellingLoc(decl_loc); 559 if (strcmp(result.SourceManager->getBufferName(spell), 560 "<scratch space>") == 0) 561 return; 562 } 563 clang::ASTContext* context = result.Context; 564 std::string new_name; 565 if (!GetNameForDecl(*decl, *context, new_name)) 566 return; // If false, the name was not suitable for renaming. 567 llvm::StringRef old_name = decl->getName(); 568 if (old_name == new_name) 569 return; 570 clang::SourceLocation loc = TargetNodeTraits<TargetNode>::GetLoc( 571 *result.Nodes.getNodeAs<TargetNode>( 572 TargetNodeTraits<TargetNode>::GetName())); 573 clang::CharSourceRange range = clang::CharSourceRange::getTokenRange(loc); 574 replacements_->emplace(*result.SourceManager, range, new_name); 575 replacement_names_.emplace(old_name.str(), std::move(new_name)); 576 } 577 578 const std::unordered_map<std::string, std::string>& replacement_names() 579 const { 580 return replacement_names_; 581 } 582 583 private: 584 std::set<Replacement>* const replacements_; 585 std::unordered_map<std::string, std::string> replacement_names_; 586 }; 587 588 using FieldDeclRewriter = RewriterBase<clang::FieldDecl, clang::NamedDecl>; 589 using VarDeclRewriter = RewriterBase<clang::VarDecl, clang::NamedDecl>; 590 using MemberRewriter = RewriterBase<clang::FieldDecl, clang::MemberExpr>; 591 using DeclRefRewriter = RewriterBase<clang::VarDecl, clang::DeclRefExpr>; 592 using FieldDeclRefRewriter = RewriterBase<clang::FieldDecl, clang::DeclRefExpr>; 593 using FunctionDeclRewriter = 594 RewriterBase<clang::FunctionDecl, clang::NamedDecl>; 595 using FunctionRefRewriter = 596 RewriterBase<clang::FunctionDecl, clang::DeclRefExpr>; 597 using ConstructorInitializerRewriter = 598 RewriterBase<clang::FieldDecl, clang::CXXCtorInitializer>; 599 600 using MethodDeclRewriter = RewriterBase<clang::CXXMethodDecl, clang::NamedDecl>; 601 using MethodRefRewriter = 602 RewriterBase<clang::CXXMethodDecl, clang::DeclRefExpr>; 603 using MethodMemberRewriter = 604 RewriterBase<clang::CXXMethodDecl, clang::MemberExpr>; 605 606 using EnumConstantDeclRewriter = 607 RewriterBase<clang::EnumConstantDecl, clang::NamedDecl>; 608 using EnumConstantDeclRefRewriter = 609 RewriterBase<clang::EnumConstantDecl, clang::DeclRefExpr>; 610 611 using UnresolvedLookupRewriter = 612 RewriterBase<clang::NamedDecl, clang::UnresolvedLookupExpr>; 613 using UnresolvedMemberRewriter = 614 RewriterBase<clang::NamedDecl, clang::UnresolvedMemberExpr>; 615 616 using UsingDeclRewriter = RewriterBase<clang::UsingDecl, clang::NamedDecl>; 617 618 } // namespace 619 620 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage); 621 622 int main(int argc, const char* argv[]) { 623 // TODO(dcheng): Clang tooling should do this itself. 624 // http://llvm.org/bugs/show_bug.cgi?id=21627 625 llvm::InitializeNativeTarget(); 626 llvm::InitializeNativeTargetAsmParser(); 627 llvm::cl::OptionCategory category( 628 "rewrite_to_chrome_style: convert Blink style to Chrome style."); 629 CommonOptionsParser options(argc, argv, category); 630 clang::tooling::ClangTool tool(options.getCompilations(), 631 options.getSourcePathList()); 632 633 MatchFinder match_finder; 634 std::set<Replacement> replacements; 635 636 // Blink namespace matchers ======== 637 auto blink_namespace_decl = 638 namespaceDecl(anyOf(hasName("blink"), hasName("WTF")), 639 hasParent(translationUnitDecl())); 640 641 // Given top-level compilation unit: 642 // namespace WTF { 643 // void foo() {} 644 // } 645 // matches |foo|. 646 auto decl_under_blink_namespace = decl(hasAncestor(blink_namespace_decl)); 647 648 // Given top-level compilation unit: 649 // void WTF::function() {} 650 // void WTF::Class::method() {} 651 // matches |WTF::function| and |WTF::Class::method| decls. 652 auto decl_has_qualifier_to_blink_namespace = 653 declaratorDecl(has(nestedNameSpecifier( 654 hasTopLevelPrefix(specifiesNamespace(blink_namespace_decl))))); 655 656 auto in_blink_namespace = decl( 657 anyOf(decl_under_blink_namespace, decl_has_qualifier_to_blink_namespace, 658 hasAncestor(decl_has_qualifier_to_blink_namespace)), 659 unless(isExpansionInFileMatching(kGeneratedFileRegex))); 660 661 // Field, variable, and enum declarations ======== 662 // Given 663 // int x; 664 // struct S { 665 // int y; 666 // enum { VALUE }; 667 // }; 668 // matches |x|, |y|, and |VALUE|. 669 auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); 670 auto is_type_trait_value = 671 varDecl(hasName("value"), hasStaticStorageDuration(), isPublic(), 672 hasType(isConstQualified()), hasType(type(anyOf( 673 booleanType(), enumType()))), 674 unless(hasAncestor(recordDecl( 675 has(cxxMethodDecl(isUserProvided(), isInstanceMethod())))))); 676 auto var_decl_matcher = 677 id("decl", varDecl(in_blink_namespace, unless(is_type_trait_value))); 678 auto enum_member_decl_matcher = 679 id("decl", enumConstantDecl(in_blink_namespace)); 680 681 FieldDeclRewriter field_decl_rewriter(&replacements); 682 match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); 683 684 VarDeclRewriter var_decl_rewriter(&replacements); 685 match_finder.addMatcher(var_decl_matcher, &var_decl_rewriter); 686 687 EnumConstantDeclRewriter enum_member_decl_rewriter(&replacements); 688 match_finder.addMatcher(enum_member_decl_matcher, &enum_member_decl_rewriter); 689 690 // Field, variable, and enum references ======== 691 // Given 692 // bool x = true; 693 // if (x) { 694 // ... 695 // } 696 // matches |x| in if (x). 697 auto member_matcher = id( 698 "expr", 699 memberExpr( 700 member(field_decl_matcher), 701 // Needed to avoid matching member references in functions (which will 702 // be an ancestor of the member reference) synthesized by the 703 // compiler, such as a synthesized copy constructor. 704 // This skips explicitly defaulted functions as well, but that's OK: 705 // there's nothing interesting to rewrite in those either. 706 unless(hasAncestor(functionDecl(isDefaulted()))))); 707 auto decl_ref_matcher = id("expr", declRefExpr(to(var_decl_matcher))); 708 auto enum_member_ref_matcher = 709 id("expr", declRefExpr(to(enum_member_decl_matcher))); 710 711 MemberRewriter member_rewriter(&replacements); 712 match_finder.addMatcher(member_matcher, &member_rewriter); 713 714 DeclRefRewriter decl_ref_rewriter(&replacements); 715 match_finder.addMatcher(decl_ref_matcher, &decl_ref_rewriter); 716 717 EnumConstantDeclRefRewriter enum_member_ref_rewriter(&replacements); 718 match_finder.addMatcher(enum_member_ref_matcher, &enum_member_ref_rewriter); 719 720 // Member references in a non-member context ======== 721 // Given 722 // struct S { 723 // typedef int U::*UnspecifiedBoolType; 724 // operator UnspecifiedBoolType() { return s_ ? &U::s_ : 0; } 725 // int s_; 726 // }; 727 // matches |&U::s_| but not |s_|. 728 auto member_ref_matcher = id("expr", declRefExpr(to(field_decl_matcher))); 729 730 FieldDeclRefRewriter member_ref_rewriter(&replacements); 731 match_finder.addMatcher(member_ref_matcher, &member_ref_rewriter); 732 733 // Non-method function declarations ======== 734 // Given 735 // void f(); 736 // struct S { 737 // void g(); 738 // }; 739 // matches |f| but not |g|. 740 auto function_decl_matcher = id( 741 "decl", 742 functionDecl( 743 unless(anyOf( 744 // Methods are covered by the method matchers. 745 cxxMethodDecl(), 746 // Out-of-line overloaded operators have special names and should 747 // never be renamed. 748 isOverloadedOperator(), 749 // Must be checked after filtering out overloaded operators to 750 // prevent asserts about the identifier not being a simple name. 751 isBlacklistedFunction())), 752 in_blink_namespace)); 753 FunctionDeclRewriter function_decl_rewriter(&replacements); 754 match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); 755 756 // Non-method function references ======== 757 // Given 758 // f(); 759 // void (*p)() = &f; 760 // matches |f()| and |&f|. 761 auto function_ref_matcher = id( 762 "expr", declRefExpr(to(function_decl_matcher), 763 // Ignore template substitutions. 764 unless(hasAncestor(substNonTypeTemplateParmExpr())))); 765 FunctionRefRewriter function_ref_rewriter(&replacements); 766 match_finder.addMatcher(function_ref_matcher, &function_ref_rewriter); 767 768 // Method declarations ======== 769 // Given 770 // struct S { 771 // void g(); 772 // }; 773 // matches |g|. 774 // For a method to be considered for rewrite, it must not override something 775 // that we're not rewriting. Any methods that we would not normally consider 776 // but that override something we are rewriting should also be rewritten. So 777 // we use includeAllOverriddenMethods() to check these rules not just for the 778 // method being matched but for the methods it overrides also. 779 auto is_blink_method = includeAllOverriddenMethods( 780 allOf(in_blink_namespace, unless(isBlacklistedMethod()))); 781 auto method_decl_matcher = id( 782 "decl", 783 cxxMethodDecl( 784 unless(anyOf( 785 // Overloaded operators have special names and should never be 786 // renamed. 787 isOverloadedOperator(), 788 // Similarly, constructors, destructors, and conversion 789 // functions should not be considered for renaming. 790 cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())), 791 // Check this last after excluding things, to avoid 792 // asserts about overriding non-blink and blink for the 793 // same method. 794 is_blink_method)); 795 MethodDeclRewriter method_decl_rewriter(&replacements); 796 match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter); 797 798 // Method references in a non-member context ======== 799 // Given 800 // S s; 801 // s.g(); 802 // void (S::*p)() = &S::g; 803 // matches |&S::g| but not |s.g()|. 804 auto method_ref_matcher = id( 805 "expr", declRefExpr(to(method_decl_matcher), 806 // Ignore template substitutions. 807 unless(hasAncestor(substNonTypeTemplateParmExpr())))); 808 809 MethodRefRewriter method_ref_rewriter(&replacements); 810 match_finder.addMatcher(method_ref_matcher, &method_ref_rewriter); 811 812 // Method references in a member context ======== 813 // Given 814 // S s; 815 // s.g(); 816 // void (S::*p)() = &S::g; 817 // matches |s.g()| but not |&S::g|. 818 auto method_member_matcher = 819 id("expr", memberExpr(member(method_decl_matcher))); 820 821 MethodMemberRewriter method_member_rewriter(&replacements); 822 match_finder.addMatcher(method_member_matcher, &method_member_rewriter); 823 824 // Initializers ======== 825 // Given 826 // struct S { 827 // int x; 828 // S() : x(2) {} 829 // }; 830 // matches each initializer in the constructor for S. 831 auto constructor_initializer_matcher = 832 cxxConstructorDecl(forEachConstructorInitializer(id( 833 "initializer", 834 cxxCtorInitializer(forAnyField(field_decl_matcher), isWritten())))); 835 836 ConstructorInitializerRewriter constructor_initializer_rewriter( 837 &replacements); 838 match_finder.addMatcher(constructor_initializer_matcher, 839 &constructor_initializer_rewriter); 840 841 // Unresolved lookup expressions ======== 842 // Given 843 // template<typename T> void F(T) { } 844 // template<void G(T)> H(T) { } 845 // H<F<int>>(...); 846 // matches |F| in |H<F<int>>|. 847 // 848 // UnresolvedLookupExprs are similar to DeclRefExprs that reference a 849 // FunctionDecl, but are used when a candidate FunctionDecl can't be selected. 850 // This commonly happens inside uninstantiated template definitions for one of 851 // two reasons: 852 // 853 // 1. If the candidate declaration is a dependent FunctionTemplateDecl, the 854 // actual overload can't be selected until template instantiation time. 855 // 2. Alternatively, there might be multiple declarations in the candidate set 856 // if the candidate function has overloads. If any of the function 857 // arguments has a dependent type, then the actual overload can't be 858 // selected until instantiation time either. 859 // 860 // Another instance where UnresolvedLookupExprs can appear is in a template 861 // argument list, like the provided example. 862 auto function_template_decl_matcher = 863 id("decl", functionTemplateDecl(templatedDecl(function_decl_matcher))); 864 auto method_template_decl_matcher = 865 id("decl", functionTemplateDecl(templatedDecl(method_decl_matcher))); 866 auto unresolved_lookup_matcher = expr(id( 867 "expr", 868 unresolvedLookupExpr( 869 // In order to automatically rename an unresolved lookup, the lookup 870 // candidates must either all be Blink functions/function templates or 871 // all be Blink methods/method templates. Otherwise, we might end up 872 // in a situation where the naming could change depending on the 873 // selected candidate. 874 anyOf(allOverloadsMatch(anyOf(function_decl_matcher, 875 function_template_decl_matcher)), 876 // Note: this matches references to methods in a non-member 877 // context, e.g. Template<&Class::Method>. This and the 878 // UnresolvedMemberExpr matcher below are analogous to how the 879 // rewriter has both a MemberRefRewriter matcher to rewrite 880 // &T::method and a MethodMemberRewriter matcher to rewriter 881 // t.method(). 882 allOverloadsMatch(anyOf(method_decl_matcher, 883 method_template_decl_matcher)))))); 884 UnresolvedLookupRewriter unresolved_lookup_rewriter(&replacements); 885 match_finder.addMatcher(unresolved_lookup_matcher, 886 &unresolved_lookup_rewriter); 887 888 // Unresolved member expressions ======== 889 // Similar to unresolved lookup expressions, but for methods in a member 890 // context, e.g. var_with_templated_type.Method(). 891 auto unresolved_member_matcher = expr(id( 892 "expr", 893 unresolvedMemberExpr( 894 // Similar to UnresolvedLookupExprs, all the candidate methods must be 895 // Blink methods/method templates. 896 allOverloadsMatch( 897 anyOf(method_decl_matcher, method_template_decl_matcher))))); 898 UnresolvedMemberRewriter unresolved_member_rewriter(&replacements); 899 match_finder.addMatcher(unresolved_member_matcher, 900 &unresolved_member_rewriter); 901 902 // Using declarations ======== 903 // Given 904 // using blink::X; 905 // matches |using blink::X|. 906 auto using_decl_matcher = id( 907 "decl", usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(anyOf( 908 var_decl_matcher, field_decl_matcher, function_decl_matcher, 909 method_decl_matcher, function_template_decl_matcher, 910 method_template_decl_matcher, enum_member_decl_matcher))))); 911 UsingDeclRewriter using_decl_rewriter(&replacements); 912 match_finder.addMatcher(using_decl_matcher, &using_decl_rewriter); 913 914 std::unique_ptr<clang::tooling::FrontendActionFactory> factory = 915 clang::tooling::newFrontendActionFactory(&match_finder); 916 int result = tool.run(factory.get()); 917 if (result != 0) 918 return result; 919 920 #if defined(_WIN32) 921 HANDLE lockfd = CreateFile("rewrite-sym.lock", GENERIC_READ, FILE_SHARE_READ, 922 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 923 OVERLAPPED overlapped = {}; 924 LockFileEx(lockfd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &overlapped); 925 #else 926 int lockfd = open("rewrite-sym.lock", O_RDWR | O_CREAT, 0666); 927 while (flock(lockfd, LOCK_EX)) { // :D 928 } 929 #endif 930 931 std::ofstream replacement_db_file("rewrite-sym.txt", 932 std::ios_base::out | std::ios_base::app); 933 for (const auto& p : field_decl_rewriter.replacement_names()) 934 replacement_db_file << "var:" << p.first << ":" << p.second << "\n"; 935 for (const auto& p : var_decl_rewriter.replacement_names()) 936 replacement_db_file << "var:" << p.first << ":" << p.second << "\n"; 937 for (const auto& p : enum_member_decl_rewriter.replacement_names()) 938 replacement_db_file << "enu:" << p.first << ":" << p.second << "\n"; 939 for (const auto& p : function_decl_rewriter.replacement_names()) 940 replacement_db_file << "fun:" << p.first << ":" << p.second << "\n"; 941 for (const auto& p : method_decl_rewriter.replacement_names()) 942 replacement_db_file << "fun:" << p.first << ":" << p.second << "\n"; 943 replacement_db_file.close(); 944 945 #if defined(_WIN32) 946 UnlockFileEx(lockfd, 0, 1, 0, &overlapped); 947 CloseHandle(lockfd); 948 #else 949 flock(lockfd, LOCK_UN); 950 close(lockfd); 951 #endif 952 953 // Serialization format is documented in tools/clang/scripts/run_tool.py 954 llvm::outs() << "==== BEGIN EDITS ====\n"; 955 for (const auto& r : replacements) { 956 std::string replacement_text = r.getReplacementText().str(); 957 std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0'); 958 llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() 959 << ":::" << r.getLength() << ":::" << replacement_text << "\n"; 960 } 961 llvm::outs() << "==== END EDITS ====\n"; 962 963 return 0; 964 } 965