hokein created this revision.
Herald added a subscriber: klimek.
This is first step to integrate qualified rename into clang-refactor.
Also a few changes to SymbolOccurrence:
- add more information to SymbolOccurrence
- remove the way of using SourceLocation as the array size
https://reviews.llvm.org/D39290
Files:
include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h
lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
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<std::string> 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<UsingDecl>(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<RenameInfo> &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<const UsingDecl *> &getUsingDecls() const {
@@ -493,7 +466,7 @@
const std::set<std::string> USRSet;
ASTContext &Context;
- std::vector<RenameInfo> RenameInfos;
+ SymbolOccurrences Occurences;
// Record all interested using declarations which contains the using-shadow
// declarations of the symbol declarations being renamed.
std::vector<const UsingDecl *> UsingDecls;
@@ -518,33 +491,39 @@
TranslationUnitDecl->getASTContext().getSourceManager();
std::vector<tooling::AtomicChange> 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";
return;
}
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<clang::TranslationUnitDecl>(
- 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;
}
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<SourceLocation> Locations)
- : Kind(Kind) {
+ : Name(Name), Kind(Kind) {
ArrayRef<std::string> 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<SourceRange[]>(Locations.size());
- RangeOrNumRanges.setBegin(
- SourceLocation::getFromRawEncoding(Locations.size()));
+ Ranges = llvm::make_unique<SourceRange[]>(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: 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 <vector>
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<SourceLocation> Locations);
@@ -70,17 +91,27 @@
OccurrenceKind getKind() const { return Kind; }
ArrayRef<SourceRange> 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<SymbolContext> getSymbolContext() const {
+ return Context;
}
private:
+ SymbolName Name;
OccurrenceKind Kind;
- std::unique_ptr<SourceRange[]> MultipleRanges;
- SourceRange RangeOrNumRanges;
+ std::unique_ptr<SourceRange[]> Ranges;
+ // Empty if the rename operation is not qualified rename.
+ llvm::Optional<SymbolContext> Context;
};
using SymbolOccurrences = std::vector<SymbolOccurrence>;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits