USRLocFinder.cpp revision 353358
133965Sjdp//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// 278828Sobrien// 3218822Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 433965Sjdp// See https://llvm.org/LICENSE.txt for license information. 533965Sjdp// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 633965Sjdp// 7130561Sobrien//===----------------------------------------------------------------------===// 833965Sjdp/// 9130561Sobrien/// \file 10130561Sobrien/// Methods for finding all instances of a USR. Our strategy is very 11130561Sobrien/// simple; we just compare the USR at every relevant AST node with the one 12130561Sobrien/// provided. 1333965Sjdp/// 14130561Sobrien//===----------------------------------------------------------------------===// 15130561Sobrien 16130561Sobrien#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" 17130561Sobrien#include "clang/AST/ASTContext.h" 1833965Sjdp#include "clang/AST/RecursiveASTVisitor.h" 19130561Sobrien#include "clang/Basic/LLVM.h" 20130561Sobrien#include "clang/Basic/SourceLocation.h" 21218822Sdim#include "clang/Basic/SourceManager.h" 2233965Sjdp#include "clang/Lex/Lexer.h" 2333965Sjdp#include "clang/Tooling/Core/Lookup.h" 2433965Sjdp#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" 2533965Sjdp#include "clang/Tooling/Refactoring/Rename/SymbolName.h" 2633965Sjdp#include "clang/Tooling/Refactoring/Rename/USRFinder.h" 2733965Sjdp#include "llvm/ADT/StringRef.h" 2833965Sjdp#include "llvm/Support/Casting.h" 2960484Sobrien#include <cstddef> 3033965Sjdp#include <set> 3133965Sjdp#include <string> 3233965Sjdp#include <vector> 3333965Sjdp 3433965Sjdpusing namespace llvm; 3533965Sjdp 3633965Sjdpnamespace clang { 3733965Sjdpnamespace tooling { 3833965Sjdp 3933965Sjdpnamespace { 4033965Sjdp 4133965Sjdp// Returns true if the given Loc is valid for edit. We don't edit the 4233965Sjdp// SourceLocations that are valid or in temporary buffer. 4333965Sjdpbool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { 4433965Sjdp if (Loc.isInvalid()) 4533965Sjdp return false; 4633965Sjdp const clang::FullSourceLoc FullLoc(Loc, SM); 4733965Sjdp std::pair<clang::FileID, unsigned> FileIdAndOffset = 4833965Sjdp FullLoc.getSpellingLoc().getDecomposedLoc(); 4933965Sjdp return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; 50218822Sdim} 5133965Sjdp 5233965Sjdp// This visitor recursively searches for all instances of a USR in a 5333965Sjdp// translation unit and stores them for later usage. 5433965Sjdpclass USRLocFindingASTVisitor 5533965Sjdp : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> { 5633965Sjdppublic: 5733965Sjdp explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, 5833965Sjdp StringRef PrevName, 5933965Sjdp const ASTContext &Context) 6033965Sjdp : RecursiveSymbolVisitor(Context.getSourceManager(), 6133965Sjdp Context.getLangOpts()), 6233965Sjdp USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { 6333965Sjdp } 6433965Sjdp 6533965Sjdp bool visitSymbolOccurrence(const NamedDecl *ND, 6633965Sjdp ArrayRef<SourceRange> NameRanges) { 6733965Sjdp if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) { 6891041Sobrien assert(NameRanges.size() == 1 && 6933965Sjdp "Multiple name pieces are not supported yet!"); 7033965Sjdp SourceLocation Loc = NameRanges[0].getBegin(); 7191041Sobrien const SourceManager &SM = Context.getSourceManager(); 7233965Sjdp // TODO: Deal with macro occurrences correctly. 7333965Sjdp if (Loc.isMacroID()) 7491041Sobrien Loc = SM.getSpellingLoc(Loc); 7533965Sjdp checkAndAddLocation(Loc); 7633965Sjdp } 7791041Sobrien return true; 7833965Sjdp } 7933965Sjdp 8091041Sobrien // Non-visitors: 8133965Sjdp 8233965Sjdp /// Returns a set of unique symbol occurrences. Duplicate or 8391041Sobrien /// overlapping occurrences are erroneous and should be reported! 8433965Sjdp SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } 8533965Sjdp 8691041Sobrienprivate: 8733965Sjdp void checkAndAddLocation(SourceLocation Loc) { 8833965Sjdp const SourceLocation BeginLoc = Loc; 8989857Sobrien const SourceLocation EndLoc = Lexer::getLocForEndOfToken( 9089857Sobrien BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); 9189857Sobrien StringRef TokenName = 9289857Sobrien Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), 9333965Sjdp Context.getSourceManager(), Context.getLangOpts()); 9433965Sjdp size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); 9533965Sjdp 9633965Sjdp // The token of the source location we find actually has the old 9733965Sjdp // name. 9833965Sjdp if (Offset != StringRef::npos) 9933965Sjdp Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, 10091041Sobrien BeginLoc.getLocWithOffset(Offset)); 101130561Sobrien } 10233965Sjdp 10391041Sobrien const std::set<std::string> USRSet; 10433965Sjdp const SymbolName PrevName; 10533965Sjdp SymbolOccurrences Occurrences; 10691041Sobrien const ASTContext &Context; 10733965Sjdp}; 10833965Sjdp 10991041SobrienSourceLocation StartLocationForType(TypeLoc TL) { 11033965Sjdp // For elaborated types (e.g. `struct a::A`) we want the portion after the 11133965Sjdp // `struct` but including the namespace qualifier, `a::`. 11291041Sobrien if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { 11391041Sobrien NestedNameSpecifierLoc NestedNameSpecifier = 11491041Sobrien ElaboratedTypeLoc.getQualifierLoc(); 11533965Sjdp if (NestedNameSpecifier.getNestedNameSpecifier()) 11633965Sjdp return NestedNameSpecifier.getBeginLoc(); 11733965Sjdp TL = TL.getNextTypeLoc(); 11833965Sjdp } 11933965Sjdp return TL.getBeginLoc(); 12033965Sjdp} 12133965Sjdp 12233965SjdpSourceLocation EndLocationForType(TypeLoc TL) { 12333965Sjdp // Dig past any namespace or keyword qualifications. 12433965Sjdp while (TL.getTypeLocClass() == TypeLoc::Elaborated || 125130561Sobrien TL.getTypeLocClass() == TypeLoc::Qualified) 126130561Sobrien TL = TL.getNextTypeLoc(); 127130561Sobrien 128130561Sobrien // The location for template specializations (e.g. Foo<int>) includes the 129130561Sobrien // templated types in its location range. We want to restrict this to just 130130561Sobrien // before the `<` character. 131130561Sobrien if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { 132130561Sobrien return TL.castAs<TemplateSpecializationTypeLoc>() 133130561Sobrien .getLAngleLoc() 134130561Sobrien .getLocWithOffset(-1); 13533965Sjdp } 13633965Sjdp return TL.getEndLoc(); 13733965Sjdp} 13833965Sjdp 13933965SjdpNestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { 14033965Sjdp // Dig past any keyword qualifications. 14133965Sjdp while (TL.getTypeLocClass() == TypeLoc::Qualified) 14233965Sjdp TL = TL.getNextTypeLoc(); 14333965Sjdp 14433965Sjdp // For elaborated types (e.g. `struct a::A`) we want the portion after the 14533965Sjdp // `struct` but including the namespace qualifier, `a::`. 14633965Sjdp if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) 14733965Sjdp return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); 14833965Sjdp return nullptr; 14933965Sjdp} 15033965Sjdp 15133965Sjdp// Find all locations identified by the given USRs for rename. 15233965Sjdp// 15333965Sjdp// This class will traverse the AST and find every AST node whose USR is in the 15433965Sjdp// given USRs' set. 15533965Sjdpclass RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { 15633965Sjdppublic: 15733965Sjdp RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) 15833965Sjdp : USRSet(USRs.begin(), USRs.end()), Context(Context) {} 15933965Sjdp 16033965Sjdp // A structure records all information of a symbol reference being renamed. 16133965Sjdp // We try to add as few prefix qualifiers as possible. 16233965Sjdp struct RenameInfo { 16333965Sjdp // The begin location of a symbol being renamed. 16433965Sjdp SourceLocation Begin; 16533965Sjdp // The end location of a symbol being renamed. 16633965Sjdp SourceLocation End; 16733965Sjdp // The declaration of a symbol being renamed (can be nullptr). 16833965Sjdp const NamedDecl *FromDecl; 16933965Sjdp // The declaration in which the nested name is contained (can be nullptr). 17033965Sjdp const Decl *Context; 17133965Sjdp // The nested name being replaced (can be nullptr). 17233965Sjdp const NestedNameSpecifier *Specifier; 17333965Sjdp // Determine whether the prefix qualifiers of the NewName should be ignored. 17433965Sjdp // Normally, we set it to true for the symbol declaration and definition to 17533965Sjdp // avoid adding prefix qualifiers. 17633965Sjdp // For example, if it is true and NewName is "a::b::foo", then the symbol 17733965Sjdp // occurrence which the RenameInfo points to will be renamed to "foo". 17833965Sjdp bool IgnorePrefixQualifers; 17933965Sjdp }; 18033965Sjdp 18133965Sjdp bool VisitNamedDecl(const NamedDecl *Decl) { 18233965Sjdp // UsingDecl has been handled in other place. 18333965Sjdp if (llvm::isa<UsingDecl>(Decl)) 18433965Sjdp return true; 18533965Sjdp 18633965Sjdp // DestructorDecl has been handled in Typeloc. 18733965Sjdp if (llvm::isa<CXXDestructorDecl>(Decl)) 18833965Sjdp return true; 18933965Sjdp 19033965Sjdp if (Decl->isImplicit()) 19133965Sjdp return true; 19233965Sjdp 19333965Sjdp if (isInUSRSet(Decl)) { 19433965Sjdp // For the case of renaming an alias template, we actually rename the 19533965Sjdp // underlying alias declaration of the template. 19633965Sjdp if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) 19733965Sjdp Decl = TAT->getTemplatedDecl(); 19833965Sjdp 19933965Sjdp auto StartLoc = Decl->getLocation(); 20033965Sjdp auto EndLoc = StartLoc; 20133965Sjdp if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 20233965Sjdp RenameInfo Info = {StartLoc, 20333965Sjdp EndLoc, 20433965Sjdp /*FromDecl=*/nullptr, 20533965Sjdp /*Context=*/nullptr, 20633965Sjdp /*Specifier=*/nullptr, 20733965Sjdp /*IgnorePrefixQualifers=*/true}; 20833965Sjdp RenameInfos.push_back(Info); 20933965Sjdp } 21033965Sjdp } 21133965Sjdp return true; 21233965Sjdp } 21333965Sjdp 21433965Sjdp bool VisitMemberExpr(const MemberExpr *Expr) { 21533965Sjdp const NamedDecl *Decl = Expr->getFoundDecl(); 21633965Sjdp auto StartLoc = Expr->getMemberLoc(); 21733965Sjdp auto EndLoc = Expr->getMemberLoc(); 21833965Sjdp if (isInUSRSet(Decl)) { 21933965Sjdp RenameInfos.push_back({StartLoc, EndLoc, 22033965Sjdp /*FromDecl=*/nullptr, 22133965Sjdp /*Context=*/nullptr, 22233965Sjdp /*Specifier=*/nullptr, 22333965Sjdp /*IgnorePrefixQualifiers=*/true}); 22433965Sjdp } 22533965Sjdp return true; 22633965Sjdp } 22733965Sjdp 22833965Sjdp bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { 22933965Sjdp // Fix the constructor initializer when renaming class members. 23033965Sjdp for (const auto *Initializer : CD->inits()) { 23133965Sjdp // Ignore implicit initializers. 23233965Sjdp if (!Initializer->isWritten()) 23333965Sjdp continue; 23433965Sjdp 23533965Sjdp if (const FieldDecl *FD = Initializer->getMember()) { 23633965Sjdp if (isInUSRSet(FD)) { 23733965Sjdp auto Loc = Initializer->getSourceLocation(); 23833965Sjdp RenameInfos.push_back({Loc, Loc, 23933965Sjdp /*FromDecl=*/nullptr, 24033965Sjdp /*Context=*/nullptr, 24133965Sjdp /*Specifier=*/nullptr, 24233965Sjdp /*IgnorePrefixQualifiers=*/true}); 24333965Sjdp } 24433965Sjdp } 24533965Sjdp } 24633965Sjdp return true; 24733965Sjdp } 24833965Sjdp 24933965Sjdp bool VisitDeclRefExpr(const DeclRefExpr *Expr) { 25033965Sjdp const NamedDecl *Decl = Expr->getFoundDecl(); 25133965Sjdp // Get the underlying declaration of the shadow declaration introduced by a 25233965Sjdp // using declaration. 25333965Sjdp if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { 25433965Sjdp Decl = UsingShadow->getTargetDecl(); 25591041Sobrien } 25633965Sjdp 25733965Sjdp auto StartLoc = Expr->getBeginLoc(); 258218822Sdim // For template function call expressions like `foo<int>()`, we want to 259218822Sdim // restrict the end of location to just before the `<` character. 260218822Sdim SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() 26133965Sjdp ? Expr->getLAngleLoc().getLocWithOffset(-1) 26233965Sjdp : Expr->getEndLoc(); 263218822Sdim 26491041Sobrien if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) { 26533965Sjdp if (isInUSRSet(MD)) { 26633965Sjdp // Handle renaming static template class methods, we only rename the 26789857Sobrien // name without prefix qualifiers and restrict the source range to the 26891041Sobrien // name. 26933965Sjdp RenameInfos.push_back({EndLoc, EndLoc, 27033965Sjdp /*FromDecl=*/nullptr, 27133965Sjdp /*Context=*/nullptr, 27233965Sjdp /*Specifier=*/nullptr, 27333965Sjdp /*IgnorePrefixQualifiers=*/true}); 27433965Sjdp return true; 27533965Sjdp } 27633965Sjdp } 27733965Sjdp 27833965Sjdp // In case of renaming an enum declaration, we have to explicitly handle 27933965Sjdp // unscoped enum constants referenced in expressions (e.g. 28033965Sjdp // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped 28133965Sjdp // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by 282130561Sobrien // TypeLoc. 28333965Sjdp if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { 28433965Sjdp // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) 28533965Sjdp // when renaming an unscoped enum declaration with a new namespace. 28689857Sobrien if (!Expr->hasQualifier()) 28789857Sobrien return true; 28889857Sobrien 28989857Sobrien if (const auto *ED = 29089857Sobrien llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { 29189857Sobrien if (ED->isScoped()) 29233965Sjdp return true; 29333965Sjdp Decl = ED; 29489857Sobrien } 29589857Sobrien // The current fix would qualify "ns1::ns2::Green" as 29633965Sjdp // "ns1::ns2::Color::Green". 29733965Sjdp // 29889857Sobrien // Get the EndLoc of the replacement by moving 1 character backward ( 29989857Sobrien // to exclude the last '::'). 30089857Sobrien // 30133965Sjdp // ns1::ns2::Green; 30233965Sjdp // ^ ^^ 30389857Sobrien // BeginLoc |EndLoc of the qualifier 30489857Sobrien // new EndLoc 30533965Sjdp EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); 30633965Sjdp assert(EndLoc.isValid() && 30789857Sobrien "The enum constant should have prefix qualifers."); 30889857Sobrien } 30989857Sobrien if (isInUSRSet(Decl) && 31089857Sobrien IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 311130561Sobrien RenameInfo Info = {StartLoc, 31233965Sjdp EndLoc, 31389857Sobrien Decl, 31489857Sobrien getClosestAncestorDecl(*Expr), 31533965Sjdp Expr->getQualifier(), 31633965Sjdp /*IgnorePrefixQualifers=*/false}; 31789857Sobrien RenameInfos.push_back(Info); 31889857Sobrien } 31933965Sjdp 32033965Sjdp return true; 32189857Sobrien } 32289857Sobrien 323130561Sobrien bool VisitUsingDecl(const UsingDecl *Using) { 32489857Sobrien for (const auto *UsingShadow : Using->shadows()) { 32533965Sjdp if (isInUSRSet(UsingShadow->getTargetDecl())) { 326130561Sobrien UsingDecls.push_back(Using); 327130561Sobrien break; 32833965Sjdp } 32989857Sobrien } 33033965Sjdp return true; 33133965Sjdp } 33289857Sobrien 33389857Sobrien bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { 33489857Sobrien if (!NestedLoc.getNestedNameSpecifier()->getAsType()) 33589857Sobrien return true; 33689857Sobrien 33789857Sobrien if (const auto *TargetDecl = 33889857Sobrien getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { 33989857Sobrien if (isInUSRSet(TargetDecl)) { 34089857Sobrien RenameInfo Info = {NestedLoc.getBeginLoc(), 34189857Sobrien EndLocationForType(NestedLoc.getTypeLoc()), 34289857Sobrien TargetDecl, 34389857Sobrien getClosestAncestorDecl(NestedLoc), 34489857Sobrien NestedLoc.getNestedNameSpecifier()->getPrefix(), 34589857Sobrien /*IgnorePrefixQualifers=*/false}; 34689857Sobrien RenameInfos.push_back(Info); 347130561Sobrien } 34833965Sjdp } 349130561Sobrien return true; 350130561Sobrien } 351130561Sobrien 352130561Sobrien bool VisitTypeLoc(TypeLoc Loc) { 353130561Sobrien auto Parents = Context.getParents(Loc); 354130561Sobrien TypeLoc ParentTypeLoc; 355130561Sobrien if (!Parents.empty()) { 356130561Sobrien // Handle cases of nested name specificier locations. 35733965Sjdp // 35833965Sjdp // The VisitNestedNameSpecifierLoc interface is not impelmented in 359130561Sobrien // RecursiveASTVisitor, we have to handle it explicitly. 360130561Sobrien if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { 36133965Sjdp VisitNestedNameSpecifierLocations(*NSL); 36233965Sjdp return true; 36389857Sobrien } 36489857Sobrien 36589857Sobrien if (const auto *TL = Parents[0].get<TypeLoc>()) 36689857Sobrien ParentTypeLoc = *TL; 36789857Sobrien } 36889857Sobrien 369130561Sobrien // Handle the outermost TypeLoc which is directly linked to the interesting 37033965Sjdp // declaration and don't handle nested name specifier locations. 37191041Sobrien if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { 37233965Sjdp if (isInUSRSet(TargetDecl)) { 37333965Sjdp // Only handle the outermost typeLoc. 37433965Sjdp // 37533965Sjdp // For a type like "a::Foo", there will be two typeLocs for it. 37633965Sjdp // One ElaboratedType, the other is RecordType: 37733965Sjdp // 37833965Sjdp // ElaboratedType 0x33b9390 'a::Foo' sugar 37933965Sjdp // `-RecordType 0x338fef0 'class a::Foo' 38033965Sjdp // `-CXXRecord 0x338fe58 'Foo' 38189857Sobrien // 38289857Sobrien // Skip if this is an inner typeLoc. 38333965Sjdp if (!ParentTypeLoc.isNull() && 38433965Sjdp isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) 38533965Sjdp return true; 38633965Sjdp 38733965Sjdp auto StartLoc = StartLocationForType(Loc); 38889857Sobrien auto EndLoc = EndLocationForType(Loc); 38989857Sobrien if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 390130561Sobrien RenameInfo Info = {StartLoc, 39133965Sjdp EndLoc, 39260484Sobrien TargetDecl, 39333965Sjdp getClosestAncestorDecl(Loc), 39460484Sobrien GetNestedNameForType(Loc), 39560484Sobrien /*IgnorePrefixQualifers=*/false}; 39660484Sobrien RenameInfos.push_back(Info); 397130561Sobrien } 398130561Sobrien return true; 39960484Sobrien } 40060484Sobrien } 40160484Sobrien 40233965Sjdp // Handle specific template class specialiation cases. 40333965Sjdp if (const auto *TemplateSpecType = 40489857Sobrien dyn_cast<TemplateSpecializationType>(Loc.getType())) { 40589857Sobrien TypeLoc TargetLoc = Loc; 406130561Sobrien if (!ParentTypeLoc.isNull()) { 40789857Sobrien if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 40889857Sobrien TargetLoc = ParentTypeLoc; 40989857Sobrien } 41089857Sobrien 41189857Sobrien if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { 41289857Sobrien TypeLoc TargetLoc = Loc; 41389857Sobrien // FIXME: Find a better way to handle this case. 41489857Sobrien // For the qualified template class specification type like 41589857Sobrien // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc 41689857Sobrien // (ElaboratedType) of the TemplateSpecializationType in order to 41789857Sobrien // catch the prefix qualifiers "ns::". 41891041Sobrien if (!ParentTypeLoc.isNull() && 41933965Sjdp llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 42033965Sjdp TargetLoc = ParentTypeLoc; 42133965Sjdp 42233965Sjdp auto StartLoc = StartLocationForType(TargetLoc); 42333965Sjdp auto EndLoc = EndLocationForType(TargetLoc); 42433965Sjdp if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 42533965Sjdp RenameInfo Info = { 42638889Sjdp StartLoc, 42733965Sjdp EndLoc, 42833965Sjdp TemplateSpecType->getTemplateName().getAsTemplateDecl(), 42933965Sjdp getClosestAncestorDecl( 43033965Sjdp ast_type_traits::DynTypedNode::create(TargetLoc)), 43133965Sjdp GetNestedNameForType(TargetLoc), 43233965Sjdp /*IgnorePrefixQualifers=*/false}; 43338889Sjdp RenameInfos.push_back(Info); 434130561Sobrien } 43533965Sjdp } 43633965Sjdp } 43733965Sjdp return true; 43833965Sjdp } 43933965Sjdp 44033965Sjdp // Returns a list of RenameInfo. 44133965Sjdp const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } 44233965Sjdp 44333965Sjdp // Returns a list of using declarations which are needed to update. 44433965Sjdp const std::vector<const UsingDecl *> &getUsingDecls() const { 44533965Sjdp return UsingDecls; 44633965Sjdp } 44733965Sjdp 44833965Sjdpprivate: 44933965Sjdp // Get the supported declaration from a given typeLoc. If the declaration type 45033965Sjdp // is not supported, returns nullptr. 45133965Sjdp const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { 45233965Sjdp if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) 45333965Sjdp return TT->getDecl(); 45433965Sjdp if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) 45533965Sjdp return RD; 45633965Sjdp if (const auto *ED = 45789857Sobrien llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) 45889857Sobrien return ED; 45933965Sjdp return nullptr; 46089857Sobrien } 46191041Sobrien 46291041Sobrien // Get the closest ancester which is a declaration of a given AST node. 46391041Sobrien template <typename ASTNodeType> 46433965Sjdp const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { 46533965Sjdp auto Parents = Context.getParents(Node); 46660484Sobrien // FIXME: figure out how to handle it when there are multiple parents. 46760484Sobrien if (Parents.size() != 1) 46833965Sjdp return nullptr; 46938889Sjdp if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf( 47038889Sjdp Parents[0].getNodeKind())) 47138889Sjdp return Parents[0].template get<Decl>(); 47233965Sjdp return getClosestAncestorDecl(Parents[0]); 47338889Sjdp } 474130561Sobrien 475130561Sobrien // Get the parent typeLoc of a given typeLoc. If there is no such parent, 476130561Sobrien // return nullptr. 477130561Sobrien const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { 478130561Sobrien auto Parents = Context.getParents(Loc); 479130561Sobrien // FIXME: figure out how to handle it when there are multiple parents. 48038889Sjdp if (Parents.size() != 1) 48138889Sjdp return nullptr; 48260484Sobrien return Parents[0].get<TypeLoc>(); 48360484Sobrien } 48460484Sobrien 48560484Sobrien // Check whether the USR of a given Decl is in the USRSet. 48660484Sobrien bool isInUSRSet(const Decl *Decl) const { 48738889Sjdp auto USR = getUSRForDecl(Decl); 48838889Sjdp if (USR.empty()) 48938889Sjdp return false; 49038889Sjdp return llvm::is_contained(USRSet, USR); 491130561Sobrien } 492130561Sobrien 493130561Sobrien const std::set<std::string> USRSet; 494130561Sobrien ASTContext &Context; 495130561Sobrien std::vector<RenameInfo> RenameInfos; 49638889Sjdp // Record all interested using declarations which contains the using-shadow 49760484Sobrien // declarations of the symbol declarations being renamed. 49838889Sjdp std::vector<const UsingDecl *> UsingDecls; 49938889Sjdp}; 50060484Sobrien 50160484Sobrien} // namespace 50260484Sobrien 50360484SobrienSymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, 50460484Sobrien StringRef PrevName, Decl *Decl) { 505218822Sdim USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); 50660484Sobrien Visitor.TraverseDecl(Decl); 507218822Sdim return Visitor.takeOccurrences(); 50860484Sobrien} 50938889Sjdp 51038889Sjdpstd::vector<tooling::AtomicChange> 51138889SjdpcreateRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, 51238889Sjdp llvm::StringRef NewName, Decl *TranslationUnitDecl) { 51338889Sjdp RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); 51438889Sjdp Finder.TraverseDecl(TranslationUnitDecl); 51560484Sobrien 51660484Sobrien const SourceManager &SM = 51760484Sobrien TranslationUnitDecl->getASTContext().getSourceManager(); 518218822Sdim 519218822Sdim std::vector<tooling::AtomicChange> AtomicChanges; 520218822Sdim auto Replace = [&](SourceLocation Start, SourceLocation End, 521218822Sdim llvm::StringRef Text) { 522218822Sdim tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); 523218822Sdim llvm::Error Err = ReplaceChange.replace( 524218822Sdim SM, CharSourceRange::getTokenRange(Start, End), Text); 525218822Sdim if (Err) { 52660484Sobrien llvm::errs() << "Failed to add replacement to AtomicChange: " 52760484Sobrien << llvm::toString(std::move(Err)) << "\n"; 52860484Sobrien return; 52938889Sjdp } 53038889Sjdp AtomicChanges.push_back(std::move(ReplaceChange)); 53138889Sjdp }; 53260484Sobrien 533218822Sdim for (const auto &RenameInfo : Finder.getRenameInfos()) { 53460484Sobrien std::string ReplacedName = NewName.str(); 53538889Sjdp if (RenameInfo.IgnorePrefixQualifers) { 53638889Sjdp // Get the name without prefix qualifiers from NewName. 53738889Sjdp size_t LastColonPos = NewName.find_last_of(':'); 53838889Sjdp if (LastColonPos != std::string::npos) 53938889Sjdp ReplacedName = NewName.substr(LastColonPos + 1); 54038889Sjdp } else { 54138889Sjdp if (RenameInfo.FromDecl && RenameInfo.Context) { 54238889Sjdp if (!llvm::isa<clang::TranslationUnitDecl>( 54338889Sjdp RenameInfo.Context->getDeclContext())) { 54433965Sjdp ReplacedName = tooling::replaceNestedName( 54533965Sjdp RenameInfo.Specifier, RenameInfo.Begin, 54633965Sjdp RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl, 54733965Sjdp NewName.startswith("::") ? NewName.str() 54833965Sjdp : ("::" + NewName).str()); 549130561Sobrien } else { 550130561Sobrien // This fixes the case where type `T` is a parameter inside a function 551130561Sobrien // type (e.g. `std::function<void(T)>`) and the DeclContext of `T` 552130561Sobrien // becomes the translation unit. As a workaround, we simply use 553130561Sobrien // fully-qualified name here for all references whose `DeclContext` is 554130561Sobrien // the translation unit and ignore the possible existence of 555130561Sobrien // using-decls (in the global scope) that can shorten the replaced 55633965Sjdp // name. 55733965Sjdp llvm::StringRef ActualName = Lexer::getSourceText( 55833965Sjdp CharSourceRange::getTokenRange( 55933965Sjdp SourceRange(RenameInfo.Begin, RenameInfo.End)), 56033965Sjdp SM, TranslationUnitDecl->getASTContext().getLangOpts()); 56133965Sjdp // Add the leading "::" back if the name written in the code contains 56233965Sjdp // it. 56333965Sjdp if (ActualName.startswith("::") && !NewName.startswith("::")) { 56433965Sjdp ReplacedName = "::" + NewName.str(); 56533965Sjdp } 56633965Sjdp } 56733965Sjdp } 56833965Sjdp // If the NewName contains leading "::", add it back. 56933965Sjdp if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) 57033965Sjdp ReplacedName = NewName.str(); 57133965Sjdp } 57233965Sjdp Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); 57333965Sjdp } 57433965Sjdp 57533965Sjdp // Hanlde using declarations explicitly as "using a::Foo" don't trigger 576130561Sobrien // typeLoc for "a::Foo". 577130561Sobrien for (const auto *Using : Finder.getUsingDecls()) 578130561Sobrien Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str()); 579130561Sobrien 580130561Sobrien return AtomicChanges; 581130561Sobrien} 58233965Sjdp 58333965Sjdp} // end namespace tooling 58433965Sjdp} // end namespace clang 58560484Sobrien