xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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