10b57cec5SDimitry Andric //===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// Methods for finding all instances of a USR. Our strategy is very 110b57cec5SDimitry Andric /// simple; we just compare the USR at every relevant AST node with the one 120b57cec5SDimitry Andric /// provided. 130b57cec5SDimitry Andric /// 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" 170b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 185ffd83dbSDimitry Andric #include "clang/AST/ParentMapContext.h" 190b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 200b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 210b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h" 220b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 230b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 24e8d8bef9SDimitry Andric #include "clang/Tooling/Refactoring/Lookup.h" 250b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" 260b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/Rename/SymbolName.h" 270b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/Rename/USRFinder.h" 280b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 290b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 300b57cec5SDimitry Andric #include <cstddef> 310b57cec5SDimitry Andric #include <set> 320b57cec5SDimitry Andric #include <string> 330b57cec5SDimitry Andric #include <vector> 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric using namespace llvm; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric namespace clang { 380b57cec5SDimitry Andric namespace tooling { 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric namespace { 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric // Returns true if the given Loc is valid for edit. We don't edit the 430b57cec5SDimitry Andric // SourceLocations that are valid or in temporary buffer. 440b57cec5SDimitry Andric bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { 450b57cec5SDimitry Andric if (Loc.isInvalid()) 460b57cec5SDimitry Andric return false; 470b57cec5SDimitry Andric const clang::FullSourceLoc FullLoc(Loc, SM); 480b57cec5SDimitry Andric std::pair<clang::FileID, unsigned> FileIdAndOffset = 490b57cec5SDimitry Andric FullLoc.getSpellingLoc().getDecomposedLoc(); 500b57cec5SDimitry Andric return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // This visitor recursively searches for all instances of a USR in a 540b57cec5SDimitry Andric // translation unit and stores them for later usage. 550b57cec5SDimitry Andric class USRLocFindingASTVisitor 560b57cec5SDimitry Andric : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> { 570b57cec5SDimitry Andric public: 580b57cec5SDimitry Andric explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, 590b57cec5SDimitry Andric StringRef PrevName, 600b57cec5SDimitry Andric const ASTContext &Context) 610b57cec5SDimitry Andric : RecursiveSymbolVisitor(Context.getSourceManager(), 620b57cec5SDimitry Andric Context.getLangOpts()), 630b57cec5SDimitry Andric USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric bool visitSymbolOccurrence(const NamedDecl *ND, 670b57cec5SDimitry Andric ArrayRef<SourceRange> NameRanges) { 680b57cec5SDimitry Andric if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) { 690b57cec5SDimitry Andric assert(NameRanges.size() == 1 && 700b57cec5SDimitry Andric "Multiple name pieces are not supported yet!"); 710b57cec5SDimitry Andric SourceLocation Loc = NameRanges[0].getBegin(); 720b57cec5SDimitry Andric const SourceManager &SM = Context.getSourceManager(); 730b57cec5SDimitry Andric // TODO: Deal with macro occurrences correctly. 740b57cec5SDimitry Andric if (Loc.isMacroID()) 750b57cec5SDimitry Andric Loc = SM.getSpellingLoc(Loc); 760b57cec5SDimitry Andric checkAndAddLocation(Loc); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric return true; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric // Non-visitors: 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric /// Returns a set of unique symbol occurrences. Duplicate or 840b57cec5SDimitry Andric /// overlapping occurrences are erroneous and should be reported! 850b57cec5SDimitry Andric SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric private: 880b57cec5SDimitry Andric void checkAndAddLocation(SourceLocation Loc) { 890b57cec5SDimitry Andric const SourceLocation BeginLoc = Loc; 900b57cec5SDimitry Andric const SourceLocation EndLoc = Lexer::getLocForEndOfToken( 910b57cec5SDimitry Andric BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); 920b57cec5SDimitry Andric StringRef TokenName = 930b57cec5SDimitry Andric Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), 940b57cec5SDimitry Andric Context.getSourceManager(), Context.getLangOpts()); 950b57cec5SDimitry Andric size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric // The token of the source location we find actually has the old 980b57cec5SDimitry Andric // name. 990b57cec5SDimitry Andric if (Offset != StringRef::npos) 1000b57cec5SDimitry Andric Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, 1010b57cec5SDimitry Andric BeginLoc.getLocWithOffset(Offset)); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric const std::set<std::string> USRSet; 1050b57cec5SDimitry Andric const SymbolName PrevName; 1060b57cec5SDimitry Andric SymbolOccurrences Occurrences; 1070b57cec5SDimitry Andric const ASTContext &Context; 1080b57cec5SDimitry Andric }; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric SourceLocation StartLocationForType(TypeLoc TL) { 1110b57cec5SDimitry Andric // For elaborated types (e.g. `struct a::A`) we want the portion after the 1120b57cec5SDimitry Andric // `struct` but including the namespace qualifier, `a::`. 1130b57cec5SDimitry Andric if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { 1140b57cec5SDimitry Andric NestedNameSpecifierLoc NestedNameSpecifier = 1150b57cec5SDimitry Andric ElaboratedTypeLoc.getQualifierLoc(); 1160b57cec5SDimitry Andric if (NestedNameSpecifier.getNestedNameSpecifier()) 1170b57cec5SDimitry Andric return NestedNameSpecifier.getBeginLoc(); 1180b57cec5SDimitry Andric TL = TL.getNextTypeLoc(); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric return TL.getBeginLoc(); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric SourceLocation EndLocationForType(TypeLoc TL) { 1240b57cec5SDimitry Andric // Dig past any namespace or keyword qualifications. 1250b57cec5SDimitry Andric while (TL.getTypeLocClass() == TypeLoc::Elaborated || 1260b57cec5SDimitry Andric TL.getTypeLocClass() == TypeLoc::Qualified) 1270b57cec5SDimitry Andric TL = TL.getNextTypeLoc(); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // The location for template specializations (e.g. Foo<int>) includes the 1300b57cec5SDimitry Andric // templated types in its location range. We want to restrict this to just 1310b57cec5SDimitry Andric // before the `<` character. 1320b57cec5SDimitry Andric if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { 1330b57cec5SDimitry Andric return TL.castAs<TemplateSpecializationTypeLoc>() 1340b57cec5SDimitry Andric .getLAngleLoc() 1350b57cec5SDimitry Andric .getLocWithOffset(-1); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric return TL.getEndLoc(); 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { 1410b57cec5SDimitry Andric // Dig past any keyword qualifications. 1420b57cec5SDimitry Andric while (TL.getTypeLocClass() == TypeLoc::Qualified) 1430b57cec5SDimitry Andric TL = TL.getNextTypeLoc(); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // For elaborated types (e.g. `struct a::A`) we want the portion after the 1460b57cec5SDimitry Andric // `struct` but including the namespace qualifier, `a::`. 1470b57cec5SDimitry Andric if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) 1480b57cec5SDimitry Andric return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); 1490b57cec5SDimitry Andric return nullptr; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric // Find all locations identified by the given USRs for rename. 1530b57cec5SDimitry Andric // 1540b57cec5SDimitry Andric // This class will traverse the AST and find every AST node whose USR is in the 1550b57cec5SDimitry Andric // given USRs' set. 1560b57cec5SDimitry Andric class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { 1570b57cec5SDimitry Andric public: 1580b57cec5SDimitry Andric RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) 1590b57cec5SDimitry Andric : USRSet(USRs.begin(), USRs.end()), Context(Context) {} 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric // A structure records all information of a symbol reference being renamed. 1620b57cec5SDimitry Andric // We try to add as few prefix qualifiers as possible. 1630b57cec5SDimitry Andric struct RenameInfo { 1640b57cec5SDimitry Andric // The begin location of a symbol being renamed. 1650b57cec5SDimitry Andric SourceLocation Begin; 1660b57cec5SDimitry Andric // The end location of a symbol being renamed. 1670b57cec5SDimitry Andric SourceLocation End; 1680b57cec5SDimitry Andric // The declaration of a symbol being renamed (can be nullptr). 1690b57cec5SDimitry Andric const NamedDecl *FromDecl; 1700b57cec5SDimitry Andric // The declaration in which the nested name is contained (can be nullptr). 1710b57cec5SDimitry Andric const Decl *Context; 1720b57cec5SDimitry Andric // The nested name being replaced (can be nullptr). 1730b57cec5SDimitry Andric const NestedNameSpecifier *Specifier; 1740b57cec5SDimitry Andric // Determine whether the prefix qualifiers of the NewName should be ignored. 1750b57cec5SDimitry Andric // Normally, we set it to true for the symbol declaration and definition to 1760b57cec5SDimitry Andric // avoid adding prefix qualifiers. 1770b57cec5SDimitry Andric // For example, if it is true and NewName is "a::b::foo", then the symbol 1780b57cec5SDimitry Andric // occurrence which the RenameInfo points to will be renamed to "foo". 1790b57cec5SDimitry Andric bool IgnorePrefixQualifers; 1800b57cec5SDimitry Andric }; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric bool VisitNamedDecl(const NamedDecl *Decl) { 1830b57cec5SDimitry Andric // UsingDecl has been handled in other place. 1840b57cec5SDimitry Andric if (llvm::isa<UsingDecl>(Decl)) 1850b57cec5SDimitry Andric return true; 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // DestructorDecl has been handled in Typeloc. 1880b57cec5SDimitry Andric if (llvm::isa<CXXDestructorDecl>(Decl)) 1890b57cec5SDimitry Andric return true; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric if (Decl->isImplicit()) 1920b57cec5SDimitry Andric return true; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric if (isInUSRSet(Decl)) { 1950b57cec5SDimitry Andric // For the case of renaming an alias template, we actually rename the 1960b57cec5SDimitry Andric // underlying alias declaration of the template. 1970b57cec5SDimitry Andric if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) 1980b57cec5SDimitry Andric Decl = TAT->getTemplatedDecl(); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric auto StartLoc = Decl->getLocation(); 2010b57cec5SDimitry Andric auto EndLoc = StartLoc; 2020b57cec5SDimitry Andric if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 2030b57cec5SDimitry Andric RenameInfo Info = {StartLoc, 2040b57cec5SDimitry Andric EndLoc, 2050b57cec5SDimitry Andric /*FromDecl=*/nullptr, 2060b57cec5SDimitry Andric /*Context=*/nullptr, 2070b57cec5SDimitry Andric /*Specifier=*/nullptr, 2080b57cec5SDimitry Andric /*IgnorePrefixQualifers=*/true}; 2090b57cec5SDimitry Andric RenameInfos.push_back(Info); 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric return true; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric bool VisitMemberExpr(const MemberExpr *Expr) { 2160b57cec5SDimitry Andric const NamedDecl *Decl = Expr->getFoundDecl(); 2170b57cec5SDimitry Andric auto StartLoc = Expr->getMemberLoc(); 2180b57cec5SDimitry Andric auto EndLoc = Expr->getMemberLoc(); 2190b57cec5SDimitry Andric if (isInUSRSet(Decl)) { 2200b57cec5SDimitry Andric RenameInfos.push_back({StartLoc, EndLoc, 2210b57cec5SDimitry Andric /*FromDecl=*/nullptr, 2220b57cec5SDimitry Andric /*Context=*/nullptr, 2230b57cec5SDimitry Andric /*Specifier=*/nullptr, 2240b57cec5SDimitry Andric /*IgnorePrefixQualifiers=*/true}); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric return true; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 229fe6060f1SDimitry Andric bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) { 230fe6060f1SDimitry Andric for (const DesignatedInitExpr::Designator &D : E->designators()) { 23106c3fb27SDimitry Andric if (D.isFieldDesignator()) { 23206c3fb27SDimitry Andric if (const FieldDecl *Decl = D.getFieldDecl()) { 233fe6060f1SDimitry Andric if (isInUSRSet(Decl)) { 234fe6060f1SDimitry Andric auto StartLoc = D.getFieldLoc(); 235fe6060f1SDimitry Andric auto EndLoc = D.getFieldLoc(); 236fe6060f1SDimitry Andric RenameInfos.push_back({StartLoc, EndLoc, 237fe6060f1SDimitry Andric /*FromDecl=*/nullptr, 238fe6060f1SDimitry Andric /*Context=*/nullptr, 239fe6060f1SDimitry Andric /*Specifier=*/nullptr, 240fe6060f1SDimitry Andric /*IgnorePrefixQualifiers=*/true}); 241fe6060f1SDimitry Andric } 242fe6060f1SDimitry Andric } 243fe6060f1SDimitry Andric } 24406c3fb27SDimitry Andric } 245fe6060f1SDimitry Andric return true; 246fe6060f1SDimitry Andric } 247fe6060f1SDimitry Andric 2480b57cec5SDimitry Andric bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { 2490b57cec5SDimitry Andric // Fix the constructor initializer when renaming class members. 2500b57cec5SDimitry Andric for (const auto *Initializer : CD->inits()) { 2510b57cec5SDimitry Andric // Ignore implicit initializers. 2520b57cec5SDimitry Andric if (!Initializer->isWritten()) 2530b57cec5SDimitry Andric continue; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric if (const FieldDecl *FD = Initializer->getMember()) { 2560b57cec5SDimitry Andric if (isInUSRSet(FD)) { 2570b57cec5SDimitry Andric auto Loc = Initializer->getSourceLocation(); 2580b57cec5SDimitry Andric RenameInfos.push_back({Loc, Loc, 2590b57cec5SDimitry Andric /*FromDecl=*/nullptr, 2600b57cec5SDimitry Andric /*Context=*/nullptr, 2610b57cec5SDimitry Andric /*Specifier=*/nullptr, 2620b57cec5SDimitry Andric /*IgnorePrefixQualifiers=*/true}); 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric return true; 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric bool VisitDeclRefExpr(const DeclRefExpr *Expr) { 2700b57cec5SDimitry Andric const NamedDecl *Decl = Expr->getFoundDecl(); 2710b57cec5SDimitry Andric // Get the underlying declaration of the shadow declaration introduced by a 2720b57cec5SDimitry Andric // using declaration. 2730b57cec5SDimitry Andric if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { 2740b57cec5SDimitry Andric Decl = UsingShadow->getTargetDecl(); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric auto StartLoc = Expr->getBeginLoc(); 2780b57cec5SDimitry Andric // For template function call expressions like `foo<int>()`, we want to 2790b57cec5SDimitry Andric // restrict the end of location to just before the `<` character. 2800b57cec5SDimitry Andric SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() 2810b57cec5SDimitry Andric ? Expr->getLAngleLoc().getLocWithOffset(-1) 2820b57cec5SDimitry Andric : Expr->getEndLoc(); 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) { 2850b57cec5SDimitry Andric if (isInUSRSet(MD)) { 2860b57cec5SDimitry Andric // Handle renaming static template class methods, we only rename the 2870b57cec5SDimitry Andric // name without prefix qualifiers and restrict the source range to the 2880b57cec5SDimitry Andric // name. 2890b57cec5SDimitry Andric RenameInfos.push_back({EndLoc, EndLoc, 2900b57cec5SDimitry Andric /*FromDecl=*/nullptr, 2910b57cec5SDimitry Andric /*Context=*/nullptr, 2920b57cec5SDimitry Andric /*Specifier=*/nullptr, 2930b57cec5SDimitry Andric /*IgnorePrefixQualifiers=*/true}); 2940b57cec5SDimitry Andric return true; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric // In case of renaming an enum declaration, we have to explicitly handle 2990b57cec5SDimitry Andric // unscoped enum constants referenced in expressions (e.g. 3000b57cec5SDimitry Andric // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped 3010b57cec5SDimitry Andric // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by 3020b57cec5SDimitry Andric // TypeLoc. 3030b57cec5SDimitry Andric if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { 3040b57cec5SDimitry Andric // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) 3050b57cec5SDimitry Andric // when renaming an unscoped enum declaration with a new namespace. 3060b57cec5SDimitry Andric if (!Expr->hasQualifier()) 3070b57cec5SDimitry Andric return true; 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric if (const auto *ED = 3100b57cec5SDimitry Andric llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { 3110b57cec5SDimitry Andric if (ED->isScoped()) 3120b57cec5SDimitry Andric return true; 3130b57cec5SDimitry Andric Decl = ED; 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric // The current fix would qualify "ns1::ns2::Green" as 3160b57cec5SDimitry Andric // "ns1::ns2::Color::Green". 3170b57cec5SDimitry Andric // 3180b57cec5SDimitry Andric // Get the EndLoc of the replacement by moving 1 character backward ( 3190b57cec5SDimitry Andric // to exclude the last '::'). 3200b57cec5SDimitry Andric // 3210b57cec5SDimitry Andric // ns1::ns2::Green; 3220b57cec5SDimitry Andric // ^ ^^ 3230b57cec5SDimitry Andric // BeginLoc |EndLoc of the qualifier 3240b57cec5SDimitry Andric // new EndLoc 3250b57cec5SDimitry Andric EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); 3260b57cec5SDimitry Andric assert(EndLoc.isValid() && 3270b57cec5SDimitry Andric "The enum constant should have prefix qualifers."); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric if (isInUSRSet(Decl) && 3300b57cec5SDimitry Andric IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 3310b57cec5SDimitry Andric RenameInfo Info = {StartLoc, 3320b57cec5SDimitry Andric EndLoc, 3330b57cec5SDimitry Andric Decl, 3340b57cec5SDimitry Andric getClosestAncestorDecl(*Expr), 3350b57cec5SDimitry Andric Expr->getQualifier(), 3360b57cec5SDimitry Andric /*IgnorePrefixQualifers=*/false}; 3370b57cec5SDimitry Andric RenameInfos.push_back(Info); 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric return true; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric bool VisitUsingDecl(const UsingDecl *Using) { 3440b57cec5SDimitry Andric for (const auto *UsingShadow : Using->shadows()) { 3450b57cec5SDimitry Andric if (isInUSRSet(UsingShadow->getTargetDecl())) { 3460b57cec5SDimitry Andric UsingDecls.push_back(Using); 3470b57cec5SDimitry Andric break; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric return true; 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { 3540b57cec5SDimitry Andric if (!NestedLoc.getNestedNameSpecifier()->getAsType()) 3550b57cec5SDimitry Andric return true; 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric if (const auto *TargetDecl = 3580b57cec5SDimitry Andric getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { 3590b57cec5SDimitry Andric if (isInUSRSet(TargetDecl)) { 3600b57cec5SDimitry Andric RenameInfo Info = {NestedLoc.getBeginLoc(), 3610b57cec5SDimitry Andric EndLocationForType(NestedLoc.getTypeLoc()), 3620b57cec5SDimitry Andric TargetDecl, 3630b57cec5SDimitry Andric getClosestAncestorDecl(NestedLoc), 3640b57cec5SDimitry Andric NestedLoc.getNestedNameSpecifier()->getPrefix(), 3650b57cec5SDimitry Andric /*IgnorePrefixQualifers=*/false}; 3660b57cec5SDimitry Andric RenameInfos.push_back(Info); 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric return true; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric bool VisitTypeLoc(TypeLoc Loc) { 3730b57cec5SDimitry Andric auto Parents = Context.getParents(Loc); 3740b57cec5SDimitry Andric TypeLoc ParentTypeLoc; 3750b57cec5SDimitry Andric if (!Parents.empty()) { 3760b57cec5SDimitry Andric // Handle cases of nested name specificier locations. 3770b57cec5SDimitry Andric // 3780b57cec5SDimitry Andric // The VisitNestedNameSpecifierLoc interface is not impelmented in 3790b57cec5SDimitry Andric // RecursiveASTVisitor, we have to handle it explicitly. 3800b57cec5SDimitry Andric if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { 3810b57cec5SDimitry Andric VisitNestedNameSpecifierLocations(*NSL); 3820b57cec5SDimitry Andric return true; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric if (const auto *TL = Parents[0].get<TypeLoc>()) 3860b57cec5SDimitry Andric ParentTypeLoc = *TL; 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric // Handle the outermost TypeLoc which is directly linked to the interesting 3900b57cec5SDimitry Andric // declaration and don't handle nested name specifier locations. 3910b57cec5SDimitry Andric if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { 3920b57cec5SDimitry Andric if (isInUSRSet(TargetDecl)) { 3930b57cec5SDimitry Andric // Only handle the outermost typeLoc. 3940b57cec5SDimitry Andric // 3950b57cec5SDimitry Andric // For a type like "a::Foo", there will be two typeLocs for it. 3960b57cec5SDimitry Andric // One ElaboratedType, the other is RecordType: 3970b57cec5SDimitry Andric // 3980b57cec5SDimitry Andric // ElaboratedType 0x33b9390 'a::Foo' sugar 3990b57cec5SDimitry Andric // `-RecordType 0x338fef0 'class a::Foo' 4000b57cec5SDimitry Andric // `-CXXRecord 0x338fe58 'Foo' 4010b57cec5SDimitry Andric // 4020b57cec5SDimitry Andric // Skip if this is an inner typeLoc. 4030b57cec5SDimitry Andric if (!ParentTypeLoc.isNull() && 4040b57cec5SDimitry Andric isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) 4050b57cec5SDimitry Andric return true; 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric auto StartLoc = StartLocationForType(Loc); 4080b57cec5SDimitry Andric auto EndLoc = EndLocationForType(Loc); 4090b57cec5SDimitry Andric if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 4100b57cec5SDimitry Andric RenameInfo Info = {StartLoc, 4110b57cec5SDimitry Andric EndLoc, 4120b57cec5SDimitry Andric TargetDecl, 4130b57cec5SDimitry Andric getClosestAncestorDecl(Loc), 4140b57cec5SDimitry Andric GetNestedNameForType(Loc), 4150b57cec5SDimitry Andric /*IgnorePrefixQualifers=*/false}; 4160b57cec5SDimitry Andric RenameInfos.push_back(Info); 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric return true; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric // Handle specific template class specialiation cases. 4230b57cec5SDimitry Andric if (const auto *TemplateSpecType = 4240b57cec5SDimitry Andric dyn_cast<TemplateSpecializationType>(Loc.getType())) { 4250b57cec5SDimitry Andric TypeLoc TargetLoc = Loc; 4260b57cec5SDimitry Andric if (!ParentTypeLoc.isNull()) { 4270b57cec5SDimitry Andric if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 4280b57cec5SDimitry Andric TargetLoc = ParentTypeLoc; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { 4320b57cec5SDimitry Andric TypeLoc TargetLoc = Loc; 4330b57cec5SDimitry Andric // FIXME: Find a better way to handle this case. 4340b57cec5SDimitry Andric // For the qualified template class specification type like 4350b57cec5SDimitry Andric // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc 4360b57cec5SDimitry Andric // (ElaboratedType) of the TemplateSpecializationType in order to 4370b57cec5SDimitry Andric // catch the prefix qualifiers "ns::". 4380b57cec5SDimitry Andric if (!ParentTypeLoc.isNull() && 4390b57cec5SDimitry Andric llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 4400b57cec5SDimitry Andric TargetLoc = ParentTypeLoc; 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric auto StartLoc = StartLocationForType(TargetLoc); 4430b57cec5SDimitry Andric auto EndLoc = EndLocationForType(TargetLoc); 4440b57cec5SDimitry Andric if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 4450b57cec5SDimitry Andric RenameInfo Info = { 4460b57cec5SDimitry Andric StartLoc, 4470b57cec5SDimitry Andric EndLoc, 4480b57cec5SDimitry Andric TemplateSpecType->getTemplateName().getAsTemplateDecl(), 4495ffd83dbSDimitry Andric getClosestAncestorDecl(DynTypedNode::create(TargetLoc)), 4500b57cec5SDimitry Andric GetNestedNameForType(TargetLoc), 4510b57cec5SDimitry Andric /*IgnorePrefixQualifers=*/false}; 4520b57cec5SDimitry Andric RenameInfos.push_back(Info); 4530b57cec5SDimitry Andric } 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric return true; 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric // Returns a list of RenameInfo. 4600b57cec5SDimitry Andric const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric // Returns a list of using declarations which are needed to update. 4630b57cec5SDimitry Andric const std::vector<const UsingDecl *> &getUsingDecls() const { 4640b57cec5SDimitry Andric return UsingDecls; 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric private: 4680b57cec5SDimitry Andric // Get the supported declaration from a given typeLoc. If the declaration type 4690b57cec5SDimitry Andric // is not supported, returns nullptr. 4700b57cec5SDimitry Andric const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { 4710b57cec5SDimitry Andric if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) 4720b57cec5SDimitry Andric return TT->getDecl(); 4730b57cec5SDimitry Andric if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) 4740b57cec5SDimitry Andric return RD; 4750b57cec5SDimitry Andric if (const auto *ED = 4760b57cec5SDimitry Andric llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) 4770b57cec5SDimitry Andric return ED; 4780b57cec5SDimitry Andric return nullptr; 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric // Get the closest ancester which is a declaration of a given AST node. 4820b57cec5SDimitry Andric template <typename ASTNodeType> 4830b57cec5SDimitry Andric const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { 4840b57cec5SDimitry Andric auto Parents = Context.getParents(Node); 4850b57cec5SDimitry Andric // FIXME: figure out how to handle it when there are multiple parents. 4860b57cec5SDimitry Andric if (Parents.size() != 1) 4870b57cec5SDimitry Andric return nullptr; 4885ffd83dbSDimitry Andric if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind())) 4890b57cec5SDimitry Andric return Parents[0].template get<Decl>(); 4900b57cec5SDimitry Andric return getClosestAncestorDecl(Parents[0]); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric // Get the parent typeLoc of a given typeLoc. If there is no such parent, 4940b57cec5SDimitry Andric // return nullptr. 4950b57cec5SDimitry Andric const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { 4960b57cec5SDimitry Andric auto Parents = Context.getParents(Loc); 4970b57cec5SDimitry Andric // FIXME: figure out how to handle it when there are multiple parents. 4980b57cec5SDimitry Andric if (Parents.size() != 1) 4990b57cec5SDimitry Andric return nullptr; 5000b57cec5SDimitry Andric return Parents[0].get<TypeLoc>(); 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric // Check whether the USR of a given Decl is in the USRSet. 5040b57cec5SDimitry Andric bool isInUSRSet(const Decl *Decl) const { 5050b57cec5SDimitry Andric auto USR = getUSRForDecl(Decl); 5060b57cec5SDimitry Andric if (USR.empty()) 5070b57cec5SDimitry Andric return false; 5080b57cec5SDimitry Andric return llvm::is_contained(USRSet, USR); 5090b57cec5SDimitry Andric } 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric const std::set<std::string> USRSet; 5120b57cec5SDimitry Andric ASTContext &Context; 5130b57cec5SDimitry Andric std::vector<RenameInfo> RenameInfos; 5140b57cec5SDimitry Andric // Record all interested using declarations which contains the using-shadow 5150b57cec5SDimitry Andric // declarations of the symbol declarations being renamed. 5160b57cec5SDimitry Andric std::vector<const UsingDecl *> UsingDecls; 5170b57cec5SDimitry Andric }; 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric } // namespace 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, 5220b57cec5SDimitry Andric StringRef PrevName, Decl *Decl) { 5230b57cec5SDimitry Andric USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); 5240b57cec5SDimitry Andric Visitor.TraverseDecl(Decl); 5250b57cec5SDimitry Andric return Visitor.takeOccurrences(); 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric std::vector<tooling::AtomicChange> 5290b57cec5SDimitry Andric createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, 5300b57cec5SDimitry Andric llvm::StringRef NewName, Decl *TranslationUnitDecl) { 5310b57cec5SDimitry Andric RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); 5320b57cec5SDimitry Andric Finder.TraverseDecl(TranslationUnitDecl); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric const SourceManager &SM = 5350b57cec5SDimitry Andric TranslationUnitDecl->getASTContext().getSourceManager(); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric std::vector<tooling::AtomicChange> AtomicChanges; 5380b57cec5SDimitry Andric auto Replace = [&](SourceLocation Start, SourceLocation End, 5390b57cec5SDimitry Andric llvm::StringRef Text) { 5400b57cec5SDimitry Andric tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); 5410b57cec5SDimitry Andric llvm::Error Err = ReplaceChange.replace( 5420b57cec5SDimitry Andric SM, CharSourceRange::getTokenRange(Start, End), Text); 5430b57cec5SDimitry Andric if (Err) { 5440b57cec5SDimitry Andric llvm::errs() << "Failed to add replacement to AtomicChange: " 5450b57cec5SDimitry Andric << llvm::toString(std::move(Err)) << "\n"; 5460b57cec5SDimitry Andric return; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric AtomicChanges.push_back(std::move(ReplaceChange)); 5490b57cec5SDimitry Andric }; 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric for (const auto &RenameInfo : Finder.getRenameInfos()) { 5520b57cec5SDimitry Andric std::string ReplacedName = NewName.str(); 5530b57cec5SDimitry Andric if (RenameInfo.IgnorePrefixQualifers) { 5540b57cec5SDimitry Andric // Get the name without prefix qualifiers from NewName. 5550b57cec5SDimitry Andric size_t LastColonPos = NewName.find_last_of(':'); 5560b57cec5SDimitry Andric if (LastColonPos != std::string::npos) 5575ffd83dbSDimitry Andric ReplacedName = std::string(NewName.substr(LastColonPos + 1)); 5580b57cec5SDimitry Andric } else { 5590b57cec5SDimitry Andric if (RenameInfo.FromDecl && RenameInfo.Context) { 5600b57cec5SDimitry Andric if (!llvm::isa<clang::TranslationUnitDecl>( 5610b57cec5SDimitry Andric RenameInfo.Context->getDeclContext())) { 5620b57cec5SDimitry Andric ReplacedName = tooling::replaceNestedName( 5630b57cec5SDimitry Andric RenameInfo.Specifier, RenameInfo.Begin, 5640b57cec5SDimitry Andric RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl, 565*5f757f3fSDimitry Andric NewName.starts_with("::") ? NewName.str() 5660b57cec5SDimitry Andric : ("::" + NewName).str()); 5670b57cec5SDimitry Andric } else { 5680b57cec5SDimitry Andric // This fixes the case where type `T` is a parameter inside a function 5690b57cec5SDimitry Andric // type (e.g. `std::function<void(T)>`) and the DeclContext of `T` 5700b57cec5SDimitry Andric // becomes the translation unit. As a workaround, we simply use 5710b57cec5SDimitry Andric // fully-qualified name here for all references whose `DeclContext` is 5720b57cec5SDimitry Andric // the translation unit and ignore the possible existence of 5730b57cec5SDimitry Andric // using-decls (in the global scope) that can shorten the replaced 5740b57cec5SDimitry Andric // name. 5750b57cec5SDimitry Andric llvm::StringRef ActualName = Lexer::getSourceText( 5760b57cec5SDimitry Andric CharSourceRange::getTokenRange( 5770b57cec5SDimitry Andric SourceRange(RenameInfo.Begin, RenameInfo.End)), 5780b57cec5SDimitry Andric SM, TranslationUnitDecl->getASTContext().getLangOpts()); 5790b57cec5SDimitry Andric // Add the leading "::" back if the name written in the code contains 5800b57cec5SDimitry Andric // it. 581*5f757f3fSDimitry Andric if (ActualName.starts_with("::") && !NewName.starts_with("::")) { 5820b57cec5SDimitry Andric ReplacedName = "::" + NewName.str(); 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric // If the NewName contains leading "::", add it back. 587*5f757f3fSDimitry Andric if (NewName.starts_with("::") && NewName.substr(2) == ReplacedName) 5880b57cec5SDimitry Andric ReplacedName = NewName.str(); 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric // Hanlde using declarations explicitly as "using a::Foo" don't trigger 5940b57cec5SDimitry Andric // typeLoc for "a::Foo". 5950b57cec5SDimitry Andric for (const auto *Using : Finder.getUsingDecls()) 5960b57cec5SDimitry Andric Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str()); 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric return AtomicChanges; 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric } // end namespace tooling 6020b57cec5SDimitry Andric } // end namespace clang 603