Index: include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h =================================================================== --- include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h +++ include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h @@ -12,14 +12,18 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include namespace clang { -namespace tooling { -class SymbolName; +class Decl; +class NamedDecl; +class NestedNameSpecifier; + +namespace tooling { /// An occurrence of a symbol in the source. /// @@ -61,6 +65,23 @@ MatchingSymbol }; + // A context for qualified rename, it is used to calculate the fewest prefix + // qualifiers for the symbol occurrence. + struct SymbolContext { + // The declaration of a symbol being renamed (can be nullptr). + const NamedDecl *FromDecl; + // The declaration in which the nested name is contained (can be nullptr). + const Decl *Context; + // The nested name being replaced (can be nullptr). + const NestedNameSpecifier *Specifier; + // Determine whether the prefix qualifiers of the NewName should be ignored. + // Normally, we set it to true for the symbol declaration and definition to + // avoid adding prefix qualifiers. + // For example, if it is true and NewName is "a::b::foo", then the symbol + // occurrence which the RenameInfo points to will be renamed to "foo". + bool IgnorePrefixQualifers; + }; + SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, ArrayRef Locations); @@ -70,17 +91,27 @@ OccurrenceKind getKind() const { return Kind; } ArrayRef getNameRanges() const { - if (MultipleRanges) { - return llvm::makeArrayRef(MultipleRanges.get(), - RangeOrNumRanges.getBegin().getRawEncoding()); - } - return RangeOrNumRanges; + return llvm::makeArrayRef(Ranges.get(), Name.getNamePieces().size()); + } + + const SymbolName& getSymbolName() const { + return Name; + } + + void setSymbolContext(SymbolContext SC) { + Context = std::move(SC); + } + + llvm::Optional getSymbolContext() const { + return Context; } private: + SymbolName Name; OccurrenceKind Kind; - std::unique_ptr MultipleRanges; - SourceRange RangeOrNumRanges; + std::unique_ptr Ranges; + // Empty if the rename operation is not qualified rename. + llvm::Optional Context; }; using SymbolOccurrences = std::vector; Index: lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp =================================================================== --- lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp +++ lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp @@ -16,21 +16,14 @@ SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, ArrayRef Locations) - : Kind(Kind) { + : Name(Name), Kind(Kind) { ArrayRef NamePieces = Name.getNamePieces(); assert(Locations.size() == NamePieces.size() && "mismatching number of locations and lengths"); assert(!Locations.empty() && "no locations"); - if (Locations.size() == 1) { - RangeOrNumRanges = SourceRange( - Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size())); - return; - } - MultipleRanges = llvm::make_unique(Locations.size()); - RangeOrNumRanges.setBegin( - SourceLocation::getFromRawEncoding(Locations.size())); + Ranges = llvm::make_unique(Locations.size()); for (const auto &Loc : llvm::enumerate(Locations)) { - MultipleRanges[Loc.index()] = SourceRange( + Ranges[Loc.index()] = SourceRange( Loc.value(), Loc.value().getLocWithOffset(NamePieces[Loc.index()].size())); } Index: lib/Tooling/Refactoring/Rename/USRLocFinder.cpp =================================================================== --- lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -158,27 +158,6 @@ RenameLocFinder(llvm::ArrayRef USRs, ASTContext &Context) : USRSet(USRs.begin(), USRs.end()), Context(Context) {} - // A structure records all information of a symbol reference being renamed. - // We try to add as few prefix qualifiers as possible. - struct RenameInfo { - // The begin location of a symbol being renamed. - SourceLocation Begin; - // The end location of a symbol being renamed. - SourceLocation End; - // The declaration of a symbol being renamed (can be nullptr). - const NamedDecl *FromDecl; - // The declaration in which the nested name is contained (can be nullptr). - const Decl *Context; - // The nested name being replaced (can be nullptr). - const NestedNameSpecifier *Specifier; - // Determine whether the prefix qualifiers of the NewName should be ignored. - // Normally, we set it to true for the symbol declaration and definition to - // avoid adding prefix qualifiers. - // For example, if it is true and NewName is "a::b::foo", then the symbol - // occurrence which the RenameInfo points to will be renamed to "foo". - bool IgnorePrefixQualifers; - }; - bool VisitNamedDecl(const NamedDecl *Decl) { // UsingDecl has been handled in other place. if (llvm::isa(Decl)) @@ -200,13 +179,7 @@ auto StartLoc = Decl->getLocation(); auto EndLoc = StartLoc; if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { - RenameInfo Info = {StartLoc, - EndLoc, - /*FromDecl=*/nullptr, - /*Context=*/nullptr, - /*Specifier=*/nullptr, - /*IgnorePrefixQualifers=*/true}; - RenameInfos.push_back(Info); + addSymbolOccurence(StartLoc, EndLoc); } } return true; @@ -217,11 +190,7 @@ auto StartLoc = Expr->getMemberLoc(); auto EndLoc = Expr->getMemberLoc(); if (isInUSRSet(Decl)) { - RenameInfos.push_back({StartLoc, EndLoc, - /*FromDecl=*/nullptr, - /*Context=*/nullptr, - /*Specifier=*/nullptr, - /*IgnorePrefixQualifiers=*/true}); + addSymbolOccurence(StartLoc, EndLoc); } return true; } @@ -236,11 +205,7 @@ if (const FieldDecl *FD = Initializer->getMember()) { if (isInUSRSet(FD)) { auto Loc = Initializer->getSourceLocation(); - RenameInfos.push_back({Loc, Loc, - /*FromDecl=*/nullptr, - /*Context=*/nullptr, - /*Specifier=*/nullptr, - /*IgnorePrefixQualifiers=*/true}); + addSymbolOccurence(Loc, Loc); } } } @@ -267,11 +232,7 @@ // Handle renaming static template class methods, we only rename the // name without prefix qualifiers and restrict the source range to the // name. - RenameInfos.push_back({EndLoc, EndLoc, - /*FromDecl=*/nullptr, - /*Context=*/nullptr, - /*Specifier=*/nullptr, - /*IgnorePrefixQualifiers=*/true}); + addSymbolOccurence(EndLoc, EndLoc); return true; } } @@ -309,13 +270,12 @@ } if (isInUSRSet(Decl) && IsValidEditLoc(Context.getSourceManager(), StartLoc)) { - RenameInfo Info = {StartLoc, + addSymbolOccurence(StartLoc, EndLoc, Decl, getClosestAncestorDecl(*Expr), Expr->getQualifier(), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + /*IgnorePrefixQualifers=*/false); } return true; @@ -338,13 +298,11 @@ if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { if (isInUSRSet(TargetDecl)) { - RenameInfo Info = {NestedLoc.getBeginLoc(), + addSymbolOccurence(NestedLoc.getBeginLoc(), EndLocationForType(NestedLoc.getTypeLoc()), - TargetDecl, - getClosestAncestorDecl(NestedLoc), + TargetDecl, getClosestAncestorDecl(NestedLoc), NestedLoc.getNestedNameSpecifier()->getPrefix(), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + /*IgnorePrefixQualifers=*/false); } } return true; @@ -388,13 +346,12 @@ auto StartLoc = StartLocationForType(Loc); auto EndLoc = EndLocationForType(Loc); if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { - RenameInfo Info = {StartLoc, + addSymbolOccurence(StartLoc, EndLoc, TargetDecl, getClosestAncestorDecl(Loc), GetNestedNameForType(Loc), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + /*IgnorePrefixQualifers=*/false); } return true; } @@ -423,23 +380,39 @@ auto StartLoc = StartLocationForType(TargetLoc); auto EndLoc = EndLocationForType(TargetLoc); if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { - RenameInfo Info = { - StartLoc, - EndLoc, + addSymbolOccurence( + StartLoc, EndLoc, TemplateSpecType->getTemplateName().getAsTemplateDecl(), getClosestAncestorDecl( ast_type_traits::DynTypedNode::create(TargetLoc)), GetNestedNameForType(TargetLoc), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + /*IgnorePrefixQualifers=*/false); } } } return true; } - // Returns a list of RenameInfo. - const std::vector &getRenameInfos() const { return RenameInfos; } + void addSymbolOccurence(SourceLocation StartLoc, SourceLocation EndLoc, + const NamedDecl *FromDecl = nullptr, + const Decl *DeclContext = nullptr, + const NestedNameSpecifier *Specifier = nullptr, + bool IgnorePrefixQualifers = true) { + const auto& SM = Context.getSourceManager(); + StringRef QualifiedName = Lexer::getSourceText( + CharSourceRange::getTokenRange(SM.getSpellingLoc(StartLoc), + SM.getSpellingLoc(EndLoc)), + SM, Context.getLangOpts()); + SymbolOccurrence::SymbolContext SC = {FromDecl, DeclContext, Specifier, + IgnorePrefixQualifers}; + SymbolOccurrence Occurrence(SymbolName(QualifiedName), + SymbolOccurrence::MatchingSymbol, + SM.getSpellingLoc(StartLoc)); + Occurrence.setSymbolContext(SC); + Occurences.push_back(std::move(Occurrence)); + } + + SymbolOccurrences takeOccurences() { return std::move(Occurences); } // Returns a list of using declarations which are needed to update. const std::vector &getUsingDecls() const { @@ -493,7 +466,7 @@ const std::set USRSet; ASTContext &Context; - std::vector RenameInfos; + SymbolOccurrences Occurences; // Record all interested using declarations which contains the using-shadow // declarations of the symbol declarations being renamed. std::vector UsingDecls; @@ -518,11 +491,10 @@ TranslationUnitDecl->getASTContext().getSourceManager(); std::vector AtomicChanges; - auto Replace = [&](SourceLocation Start, SourceLocation End, - llvm::StringRef Text) { - tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); - llvm::Error Err = ReplaceChange.replace( - SM, CharSourceRange::getTokenRange(Start, End), Text); + auto Replace = [&](CharSourceRange Range, llvm::StringRef Text) { + tooling::AtomicChange ReplaceChange = tooling::AtomicChange( + SM, Range.getBegin()); + llvm::Error Err = ReplaceChange.replace(SM, Range, Text); if (Err) { llvm::errs() << "Faile to add replacement to AtomicChange: " << llvm::toString(std::move(Err)) << "\n"; @@ -531,20 +503,27 @@ AtomicChanges.push_back(std::move(ReplaceChange)); }; - for (const auto &RenameInfo : Finder.getRenameInfos()) { + for (const auto &Occurrence: Finder.takeOccurences()) { std::string ReplacedName = NewName.str(); - if (RenameInfo.IgnorePrefixQualifers) { + assert(Occurrence.getSymbolContext() && + "Occurrence in qualified rename should have Context."); + assert(Occurrence.getSymbolName().getNamePieces().size() == 1 && + "Qualified rename doesn't support symbol name composed of " + "multiple strings."); + const auto& OccurrenceContext = *Occurrence.getSymbolContext(); + if (OccurrenceContext.IgnorePrefixQualifers) { // Get the name without prefix qualifiers from NewName. size_t LastColonPos = NewName.find_last_of(':'); if (LastColonPos != std::string::npos) ReplacedName = NewName.substr(LastColonPos + 1); } else { - if (RenameInfo.FromDecl && RenameInfo.Context) { + if (OccurrenceContext.FromDecl && OccurrenceContext.Context) { if (!llvm::isa( - RenameInfo.Context->getDeclContext())) { + OccurrenceContext.Context->getDeclContext())) { ReplacedName = tooling::replaceNestedName( - RenameInfo.Specifier, RenameInfo.Context->getDeclContext(), - RenameInfo.FromDecl, + OccurrenceContext.Specifier, + OccurrenceContext.Context->getDeclContext(), + OccurrenceContext.FromDecl, NewName.startswith("::") ? NewName.str() : ("::" + NewName).str()); } else { @@ -555,10 +534,8 @@ // the translation unit and ignore the possible existence of // using-decls (in the global scope) that can shorten the replaced // name. - llvm::StringRef ActualName = Lexer::getSourceText( - CharSourceRange::getTokenRange( - SourceRange(RenameInfo.Begin, RenameInfo.End)), - SM, TranslationUnitDecl->getASTContext().getLangOpts()); + llvm::StringRef ActualName = + Occurrence.getSymbolName().getNamePieces()[0]; // Add the leading "::" back if the name written in the code contains // it. if (ActualName.startswith("::") && !NewName.startswith("::")) { @@ -570,13 +547,18 @@ if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) ReplacedName = NewName.str(); } - Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); + Replace( + CharSourceRange::getCharRange(Occurrence.getNameRanges()[0].getBegin(), + Occurrence.getNameRanges()[0].getEnd()), + ReplacedName); } // Hanlde using declarations explicitly as "using a::Foo" don't trigger // typeLoc for "a::Foo". for (const auto *Using : Finder.getUsingDecls()) - Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str()); + Replace(CharSourceRange::getTokenRange(Using->getLocStart(), + Using->getLocEnd()), + "using " + NewName.str()); return AtomicChanges; }