1 //===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Methods for finding all instances of a USR. Our strategy is very 11 /// simple; we just compare the USR at every relevant AST node with the one 12 /// provided. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/ParentMapContext.h" 19 #include "clang/AST/RecursiveASTVisitor.h" 20 #include "clang/Basic/LLVM.h" 21 #include "clang/Basic/SourceLocation.h" 22 #include "clang/Basic/SourceManager.h" 23 #include "clang/Lex/Lexer.h" 24 #include "clang/Tooling/Refactoring/Lookup.h" 25 #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" 26 #include "clang/Tooling/Refactoring/Rename/SymbolName.h" 27 #include "clang/Tooling/Refactoring/Rename/USRFinder.h" 28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/Support/Casting.h" 30 #include <cstddef> 31 #include <set> 32 #include <string> 33 #include <vector> 34 35 using namespace llvm; 36 37 namespace clang { 38 namespace tooling { 39 40 namespace { 41 42 // Returns true if the given Loc is valid for edit. We don't edit the 43 // SourceLocations that are valid or in temporary buffer. 44 bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { 45 if (Loc.isInvalid()) 46 return false; 47 const clang::FullSourceLoc FullLoc(Loc, SM); 48 std::pair<clang::FileID, unsigned> FileIdAndOffset = 49 FullLoc.getSpellingLoc().getDecomposedLoc(); 50 return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; 51 } 52 53 // This visitor recursively searches for all instances of a USR in a 54 // translation unit and stores them for later usage. 55 class USRLocFindingASTVisitor 56 : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> { 57 public: 58 explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, 59 StringRef PrevName, 60 const ASTContext &Context) 61 : RecursiveSymbolVisitor(Context.getSourceManager(), 62 Context.getLangOpts()), 63 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { 64 } 65 66 bool visitSymbolOccurrence(const NamedDecl *ND, 67 ArrayRef<SourceRange> NameRanges) { 68 if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) { 69 assert(NameRanges.size() == 1 && 70 "Multiple name pieces are not supported yet!"); 71 SourceLocation Loc = NameRanges[0].getBegin(); 72 const SourceManager &SM = Context.getSourceManager(); 73 // TODO: Deal with macro occurrences correctly. 74 if (Loc.isMacroID()) 75 Loc = SM.getSpellingLoc(Loc); 76 checkAndAddLocation(Loc); 77 } 78 return true; 79 } 80 81 // Non-visitors: 82 83 /// Returns a set of unique symbol occurrences. Duplicate or 84 /// overlapping occurrences are erroneous and should be reported! 85 SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } 86 87 private: 88 void checkAndAddLocation(SourceLocation Loc) { 89 const SourceLocation BeginLoc = Loc; 90 const SourceLocation EndLoc = Lexer::getLocForEndOfToken( 91 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); 92 StringRef TokenName = 93 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), 94 Context.getSourceManager(), Context.getLangOpts()); 95 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); 96 97 // The token of the source location we find actually has the old 98 // name. 99 if (Offset != StringRef::npos) 100 Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, 101 BeginLoc.getLocWithOffset(Offset)); 102 } 103 104 const std::set<std::string> USRSet; 105 const SymbolName PrevName; 106 SymbolOccurrences Occurrences; 107 const ASTContext &Context; 108 }; 109 110 SourceLocation StartLocationForType(TypeLoc TL) { 111 // For elaborated types (e.g. `struct a::A`) we want the portion after the 112 // `struct` but including the namespace qualifier, `a::`. 113 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { 114 NestedNameSpecifierLoc NestedNameSpecifier = 115 ElaboratedTypeLoc.getQualifierLoc(); 116 if (NestedNameSpecifier.getNestedNameSpecifier()) 117 return NestedNameSpecifier.getBeginLoc(); 118 TL = TL.getNextTypeLoc(); 119 } 120 return TL.getBeginLoc(); 121 } 122 123 SourceLocation EndLocationForType(TypeLoc TL) { 124 // Dig past any namespace or keyword qualifications. 125 while (TL.getTypeLocClass() == TypeLoc::Elaborated || 126 TL.getTypeLocClass() == TypeLoc::Qualified) 127 TL = TL.getNextTypeLoc(); 128 129 // The location for template specializations (e.g. Foo<int>) includes the 130 // templated types in its location range. We want to restrict this to just 131 // before the `<` character. 132 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { 133 return TL.castAs<TemplateSpecializationTypeLoc>() 134 .getLAngleLoc() 135 .getLocWithOffset(-1); 136 } 137 return TL.getEndLoc(); 138 } 139 140 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { 141 // Dig past any keyword qualifications. 142 while (TL.getTypeLocClass() == TypeLoc::Qualified) 143 TL = TL.getNextTypeLoc(); 144 145 // For elaborated types (e.g. `struct a::A`) we want the portion after the 146 // `struct` but including the namespace qualifier, `a::`. 147 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) 148 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); 149 return nullptr; 150 } 151 152 // Find all locations identified by the given USRs for rename. 153 // 154 // This class will traverse the AST and find every AST node whose USR is in the 155 // given USRs' set. 156 class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { 157 public: 158 RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) 159 : USRSet(USRs.begin(), USRs.end()), Context(Context) {} 160 161 // A structure records all information of a symbol reference being renamed. 162 // We try to add as few prefix qualifiers as possible. 163 struct RenameInfo { 164 // The begin location of a symbol being renamed. 165 SourceLocation Begin; 166 // The end location of a symbol being renamed. 167 SourceLocation End; 168 // The declaration of a symbol being renamed (can be nullptr). 169 const NamedDecl *FromDecl; 170 // The declaration in which the nested name is contained (can be nullptr). 171 const Decl *Context; 172 // The nested name being replaced (can be nullptr). 173 const NestedNameSpecifier *Specifier; 174 // Determine whether the prefix qualifiers of the NewName should be ignored. 175 // Normally, we set it to true for the symbol declaration and definition to 176 // avoid adding prefix qualifiers. 177 // For example, if it is true and NewName is "a::b::foo", then the symbol 178 // occurrence which the RenameInfo points to will be renamed to "foo". 179 bool IgnorePrefixQualifers; 180 }; 181 182 bool VisitNamedDecl(const NamedDecl *Decl) { 183 // UsingDecl has been handled in other place. 184 if (llvm::isa<UsingDecl>(Decl)) 185 return true; 186 187 // DestructorDecl has been handled in Typeloc. 188 if (llvm::isa<CXXDestructorDecl>(Decl)) 189 return true; 190 191 if (Decl->isImplicit()) 192 return true; 193 194 if (isInUSRSet(Decl)) { 195 // For the case of renaming an alias template, we actually rename the 196 // underlying alias declaration of the template. 197 if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) 198 Decl = TAT->getTemplatedDecl(); 199 200 auto StartLoc = Decl->getLocation(); 201 auto EndLoc = StartLoc; 202 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 203 RenameInfo Info = {StartLoc, 204 EndLoc, 205 /*FromDecl=*/nullptr, 206 /*Context=*/nullptr, 207 /*Specifier=*/nullptr, 208 /*IgnorePrefixQualifers=*/true}; 209 RenameInfos.push_back(Info); 210 } 211 } 212 return true; 213 } 214 215 bool VisitMemberExpr(const MemberExpr *Expr) { 216 const NamedDecl *Decl = Expr->getFoundDecl(); 217 auto StartLoc = Expr->getMemberLoc(); 218 auto EndLoc = Expr->getMemberLoc(); 219 if (isInUSRSet(Decl)) { 220 RenameInfos.push_back({StartLoc, EndLoc, 221 /*FromDecl=*/nullptr, 222 /*Context=*/nullptr, 223 /*Specifier=*/nullptr, 224 /*IgnorePrefixQualifiers=*/true}); 225 } 226 return true; 227 } 228 229 bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) { 230 for (const DesignatedInitExpr::Designator &D : E->designators()) { 231 if (D.isFieldDesignator()) { 232 if (const FieldDecl *Decl = D.getFieldDecl()) { 233 if (isInUSRSet(Decl)) { 234 auto StartLoc = D.getFieldLoc(); 235 auto EndLoc = D.getFieldLoc(); 236 RenameInfos.push_back({StartLoc, EndLoc, 237 /*FromDecl=*/nullptr, 238 /*Context=*/nullptr, 239 /*Specifier=*/nullptr, 240 /*IgnorePrefixQualifiers=*/true}); 241 } 242 } 243 } 244 } 245 return true; 246 } 247 248 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { 249 // Fix the constructor initializer when renaming class members. 250 for (const auto *Initializer : CD->inits()) { 251 // Ignore implicit initializers. 252 if (!Initializer->isWritten()) 253 continue; 254 255 if (const FieldDecl *FD = Initializer->getMember()) { 256 if (isInUSRSet(FD)) { 257 auto Loc = Initializer->getSourceLocation(); 258 RenameInfos.push_back({Loc, Loc, 259 /*FromDecl=*/nullptr, 260 /*Context=*/nullptr, 261 /*Specifier=*/nullptr, 262 /*IgnorePrefixQualifiers=*/true}); 263 } 264 } 265 } 266 return true; 267 } 268 269 bool VisitDeclRefExpr(const DeclRefExpr *Expr) { 270 const NamedDecl *Decl = Expr->getFoundDecl(); 271 // Get the underlying declaration of the shadow declaration introduced by a 272 // using declaration. 273 if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { 274 Decl = UsingShadow->getTargetDecl(); 275 } 276 277 auto StartLoc = Expr->getBeginLoc(); 278 // For template function call expressions like `foo<int>()`, we want to 279 // restrict the end of location to just before the `<` character. 280 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() 281 ? Expr->getLAngleLoc().getLocWithOffset(-1) 282 : Expr->getEndLoc(); 283 284 if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) { 285 if (isInUSRSet(MD)) { 286 // Handle renaming static template class methods, we only rename the 287 // name without prefix qualifiers and restrict the source range to the 288 // name. 289 RenameInfos.push_back({EndLoc, EndLoc, 290 /*FromDecl=*/nullptr, 291 /*Context=*/nullptr, 292 /*Specifier=*/nullptr, 293 /*IgnorePrefixQualifiers=*/true}); 294 return true; 295 } 296 } 297 298 // In case of renaming an enum declaration, we have to explicitly handle 299 // unscoped enum constants referenced in expressions (e.g. 300 // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped 301 // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by 302 // TypeLoc. 303 if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { 304 // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) 305 // when renaming an unscoped enum declaration with a new namespace. 306 if (!Expr->hasQualifier()) 307 return true; 308 309 if (const auto *ED = 310 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { 311 if (ED->isScoped()) 312 return true; 313 Decl = ED; 314 } 315 // The current fix would qualify "ns1::ns2::Green" as 316 // "ns1::ns2::Color::Green". 317 // 318 // Get the EndLoc of the replacement by moving 1 character backward ( 319 // to exclude the last '::'). 320 // 321 // ns1::ns2::Green; 322 // ^ ^^ 323 // BeginLoc |EndLoc of the qualifier 324 // new EndLoc 325 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); 326 assert(EndLoc.isValid() && 327 "The enum constant should have prefix qualifers."); 328 } 329 if (isInUSRSet(Decl) && 330 IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 331 RenameInfo Info = {StartLoc, 332 EndLoc, 333 Decl, 334 getClosestAncestorDecl(*Expr), 335 Expr->getQualifier(), 336 /*IgnorePrefixQualifers=*/false}; 337 RenameInfos.push_back(Info); 338 } 339 340 return true; 341 } 342 343 bool VisitUsingDecl(const UsingDecl *Using) { 344 for (const auto *UsingShadow : Using->shadows()) { 345 if (isInUSRSet(UsingShadow->getTargetDecl())) { 346 UsingDecls.push_back(Using); 347 break; 348 } 349 } 350 return true; 351 } 352 353 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { 354 if (!NestedLoc.getNestedNameSpecifier()->getAsType()) 355 return true; 356 357 if (const auto *TargetDecl = 358 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { 359 if (isInUSRSet(TargetDecl)) { 360 RenameInfo Info = {NestedLoc.getBeginLoc(), 361 EndLocationForType(NestedLoc.getTypeLoc()), 362 TargetDecl, 363 getClosestAncestorDecl(NestedLoc), 364 NestedLoc.getNestedNameSpecifier()->getPrefix(), 365 /*IgnorePrefixQualifers=*/false}; 366 RenameInfos.push_back(Info); 367 } 368 } 369 return true; 370 } 371 372 bool VisitTypeLoc(TypeLoc Loc) { 373 auto Parents = Context.getParents(Loc); 374 TypeLoc ParentTypeLoc; 375 if (!Parents.empty()) { 376 // Handle cases of nested name specificier locations. 377 // 378 // The VisitNestedNameSpecifierLoc interface is not impelmented in 379 // RecursiveASTVisitor, we have to handle it explicitly. 380 if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { 381 VisitNestedNameSpecifierLocations(*NSL); 382 return true; 383 } 384 385 if (const auto *TL = Parents[0].get<TypeLoc>()) 386 ParentTypeLoc = *TL; 387 } 388 389 // Handle the outermost TypeLoc which is directly linked to the interesting 390 // declaration and don't handle nested name specifier locations. 391 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { 392 if (isInUSRSet(TargetDecl)) { 393 // Only handle the outermost typeLoc. 394 // 395 // For a type like "a::Foo", there will be two typeLocs for it. 396 // One ElaboratedType, the other is RecordType: 397 // 398 // ElaboratedType 0x33b9390 'a::Foo' sugar 399 // `-RecordType 0x338fef0 'class a::Foo' 400 // `-CXXRecord 0x338fe58 'Foo' 401 // 402 // Skip if this is an inner typeLoc. 403 if (!ParentTypeLoc.isNull() && 404 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) 405 return true; 406 407 auto StartLoc = StartLocationForType(Loc); 408 auto EndLoc = EndLocationForType(Loc); 409 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 410 RenameInfo Info = {StartLoc, 411 EndLoc, 412 TargetDecl, 413 getClosestAncestorDecl(Loc), 414 GetNestedNameForType(Loc), 415 /*IgnorePrefixQualifers=*/false}; 416 RenameInfos.push_back(Info); 417 } 418 return true; 419 } 420 } 421 422 // Handle specific template class specialiation cases. 423 if (const auto *TemplateSpecType = 424 dyn_cast<TemplateSpecializationType>(Loc.getType())) { 425 TypeLoc TargetLoc = Loc; 426 if (!ParentTypeLoc.isNull()) { 427 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 428 TargetLoc = ParentTypeLoc; 429 } 430 431 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { 432 TypeLoc TargetLoc = Loc; 433 // FIXME: Find a better way to handle this case. 434 // For the qualified template class specification type like 435 // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc 436 // (ElaboratedType) of the TemplateSpecializationType in order to 437 // catch the prefix qualifiers "ns::". 438 if (!ParentTypeLoc.isNull() && 439 llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 440 TargetLoc = ParentTypeLoc; 441 442 auto StartLoc = StartLocationForType(TargetLoc); 443 auto EndLoc = EndLocationForType(TargetLoc); 444 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 445 RenameInfo Info = { 446 StartLoc, 447 EndLoc, 448 TemplateSpecType->getTemplateName().getAsTemplateDecl(), 449 getClosestAncestorDecl(DynTypedNode::create(TargetLoc)), 450 GetNestedNameForType(TargetLoc), 451 /*IgnorePrefixQualifers=*/false}; 452 RenameInfos.push_back(Info); 453 } 454 } 455 } 456 return true; 457 } 458 459 // Returns a list of RenameInfo. 460 const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } 461 462 // Returns a list of using declarations which are needed to update. 463 const std::vector<const UsingDecl *> &getUsingDecls() const { 464 return UsingDecls; 465 } 466 467 private: 468 // Get the supported declaration from a given typeLoc. If the declaration type 469 // is not supported, returns nullptr. 470 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { 471 if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) 472 return TT->getDecl(); 473 if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) 474 return RD; 475 if (const auto *ED = 476 llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) 477 return ED; 478 return nullptr; 479 } 480 481 // Get the closest ancester which is a declaration of a given AST node. 482 template <typename ASTNodeType> 483 const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { 484 auto Parents = Context.getParents(Node); 485 // FIXME: figure out how to handle it when there are multiple parents. 486 if (Parents.size() != 1) 487 return nullptr; 488 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind())) 489 return Parents[0].template get<Decl>(); 490 return getClosestAncestorDecl(Parents[0]); 491 } 492 493 // Get the parent typeLoc of a given typeLoc. If there is no such parent, 494 // return nullptr. 495 const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { 496 auto Parents = Context.getParents(Loc); 497 // FIXME: figure out how to handle it when there are multiple parents. 498 if (Parents.size() != 1) 499 return nullptr; 500 return Parents[0].get<TypeLoc>(); 501 } 502 503 // Check whether the USR of a given Decl is in the USRSet. 504 bool isInUSRSet(const Decl *Decl) const { 505 auto USR = getUSRForDecl(Decl); 506 if (USR.empty()) 507 return false; 508 return llvm::is_contained(USRSet, USR); 509 } 510 511 const std::set<std::string> USRSet; 512 ASTContext &Context; 513 std::vector<RenameInfo> RenameInfos; 514 // Record all interested using declarations which contains the using-shadow 515 // declarations of the symbol declarations being renamed. 516 std::vector<const UsingDecl *> UsingDecls; 517 }; 518 519 } // namespace 520 521 SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, 522 StringRef PrevName, Decl *Decl) { 523 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); 524 Visitor.TraverseDecl(Decl); 525 return Visitor.takeOccurrences(); 526 } 527 528 std::vector<tooling::AtomicChange> 529 createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, 530 llvm::StringRef NewName, Decl *TranslationUnitDecl) { 531 RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); 532 Finder.TraverseDecl(TranslationUnitDecl); 533 534 const SourceManager &SM = 535 TranslationUnitDecl->getASTContext().getSourceManager(); 536 537 std::vector<tooling::AtomicChange> AtomicChanges; 538 auto Replace = [&](SourceLocation Start, SourceLocation End, 539 llvm::StringRef Text) { 540 tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); 541 llvm::Error Err = ReplaceChange.replace( 542 SM, CharSourceRange::getTokenRange(Start, End), Text); 543 if (Err) { 544 llvm::errs() << "Failed to add replacement to AtomicChange: " 545 << llvm::toString(std::move(Err)) << "\n"; 546 return; 547 } 548 AtomicChanges.push_back(std::move(ReplaceChange)); 549 }; 550 551 for (const auto &RenameInfo : Finder.getRenameInfos()) { 552 std::string ReplacedName = NewName.str(); 553 if (RenameInfo.IgnorePrefixQualifers) { 554 // Get the name without prefix qualifiers from NewName. 555 size_t LastColonPos = NewName.find_last_of(':'); 556 if (LastColonPos != std::string::npos) 557 ReplacedName = std::string(NewName.substr(LastColonPos + 1)); 558 } else { 559 if (RenameInfo.FromDecl && RenameInfo.Context) { 560 if (!llvm::isa<clang::TranslationUnitDecl>( 561 RenameInfo.Context->getDeclContext())) { 562 ReplacedName = tooling::replaceNestedName( 563 RenameInfo.Specifier, RenameInfo.Begin, 564 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl, 565 NewName.startswith("::") ? NewName.str() 566 : ("::" + NewName).str()); 567 } else { 568 // This fixes the case where type `T` is a parameter inside a function 569 // type (e.g. `std::function<void(T)>`) and the DeclContext of `T` 570 // becomes the translation unit. As a workaround, we simply use 571 // fully-qualified name here for all references whose `DeclContext` is 572 // the translation unit and ignore the possible existence of 573 // using-decls (in the global scope) that can shorten the replaced 574 // name. 575 llvm::StringRef ActualName = Lexer::getSourceText( 576 CharSourceRange::getTokenRange( 577 SourceRange(RenameInfo.Begin, RenameInfo.End)), 578 SM, TranslationUnitDecl->getASTContext().getLangOpts()); 579 // Add the leading "::" back if the name written in the code contains 580 // it. 581 if (ActualName.startswith("::") && !NewName.startswith("::")) { 582 ReplacedName = "::" + NewName.str(); 583 } 584 } 585 } 586 // If the NewName contains leading "::", add it back. 587 if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) 588 ReplacedName = NewName.str(); 589 } 590 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); 591 } 592 593 // Hanlde using declarations explicitly as "using a::Foo" don't trigger 594 // typeLoc for "a::Foo". 595 for (const auto *Using : Finder.getUsingDecls()) 596 Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str()); 597 598 return AtomicChanges; 599 } 600 601 } // end namespace tooling 602 } // end namespace clang 603