diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-08-14 16:19:24 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-08-14 16:19:24 +0000 |
commit | 44b94c7eb3dcd7b642934805f13c96c50867accd (patch) | |
tree | 7cf9997a6ef3f07c75182f269f16a844b7169500 /clang/lib/Tooling/Refactoring/Rename | |
parent | 325ff7c5e00760b111d455608c7bf2257d093f95 (diff) | |
download | bcm5719-llvm-44b94c7eb3dcd7b642934805f13c96c50867accd.tar.gz bcm5719-llvm-44b94c7eb3dcd7b642934805f13c96c50867accd.zip |
[rename] Introduce symbol occurrences
Symbol occurrences store the results of local rename and will also be used for
the global, indexed rename results. Their kind is used to determine whether they
should be renamed automatically or not. They can be converted to a set of
AtomicChanges as well.
Differential Revision: https://reviews.llvm.org/D36156
llvm-svn: 310853
Diffstat (limited to 'clang/lib/Tooling/Refactoring/Rename')
3 files changed, 107 insertions, 39 deletions
diff --git a/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp index de6aba944a4..f4f4befc5d7 100644 --- a/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp +++ b/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp @@ -24,6 +24,7 @@ #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" #include <string> #include <vector> @@ -32,6 +33,45 @@ using namespace llvm; namespace clang { namespace tooling { +Expected<std::vector<AtomicChange>> +createRenameReplacements(const SymbolOccurrences &Occurrences, + const SourceManager &SM, + ArrayRef<StringRef> NewNameStrings) { + // FIXME: A true local rename can use just one AtomicChange. + std::vector<AtomicChange> Changes; + for (const auto &Occurrence : Occurrences) { + ArrayRef<SourceRange> Ranges = Occurrence.getNameRanges(); + assert(NewNameStrings.size() == Ranges.size() && + "Mismatching number of ranges and name pieces"); + AtomicChange Change(SM, Ranges[0].getBegin()); + for (const auto &Range : llvm::enumerate(Ranges)) { + auto Error = + Change.replace(SM, CharSourceRange::getCharRange(Range.value()), + NewNameStrings[Range.index()]); + if (Error) + return std::move(Error); + } + Changes.push_back(std::move(Change)); + } + return Changes; +} + +/// Takes each atomic change and inserts its replacements into the set of +/// replacements that belong to the appropriate file. +static void convertChangesToFileReplacements( + ArrayRef<AtomicChange> AtomicChanges, + std::map<std::string, tooling::Replacements> *FileToReplaces) { + for (const auto &AtomicChange : AtomicChanges) { + for (const auto &Replace : AtomicChange.getReplacements()) { + llvm::Error Err = (*FileToReplaces)[Replace.getFilePath()].add(Replace); + if (Err) { + llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " + << llvm::toString(std::move(Err)) << "\n"; + } + } + } +} + class RenamingASTConsumer : public ASTConsumer { public: RenamingASTConsumer( @@ -52,29 +92,29 @@ public: const std::string &PrevName, const std::vector<std::string> &USRs) { const SourceManager &SourceMgr = Context.getSourceManager(); - std::vector<SourceLocation> RenamingCandidates; - std::vector<SourceLocation> NewCandidates; - NewCandidates = tooling::getLocationsOfUSRs( + SymbolOccurrences Occurrences = tooling::getOccurrencesOfUSRs( USRs, PrevName, Context.getTranslationUnitDecl()); - RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(), - NewCandidates.end()); - - unsigned PrevNameLen = PrevName.length(); - for (const auto &Loc : RenamingCandidates) { - if (PrintLocations) { - FullSourceLoc FullLoc(Loc, SourceMgr); - errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) + if (PrintLocations) { + for (const auto &Occurrence : Occurrences) { + FullSourceLoc FullLoc(Occurrence.getNameRanges()[0].getBegin(), + SourceMgr); + errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(FullLoc) << ":" << FullLoc.getSpellingLineNumber() << ":" << FullLoc.getSpellingColumnNumber() << "\n"; } - // FIXME: better error handling. - tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName); - llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); - if (Err) - llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! " - << llvm::toString(std::move(Err)) << "\n"; } + // FIXME: Support multi-piece names. + // FIXME: better error handling (propagate error out). + StringRef NewNameRef = NewName; + Expected<std::vector<AtomicChange>> Change = + createRenameReplacements(Occurrences, SourceMgr, NewNameRef); + if (!Change) { + llvm::errs() << "Failed to create renaming replacements for '" << PrevName + << "'! " << llvm::toString(Change.takeError()) << "\n"; + return; + } + convertChangesToFileReplacements(*Change, &FileToReplaces); } private: @@ -103,15 +143,7 @@ public: // ready. auto AtomicChanges = tooling::createRenameAtomicChanges( USRList[I], NewNames[I], Context.getTranslationUnitDecl()); - for (const auto AtomicChange : AtomicChanges) { - for (const auto &Replace : AtomicChange.getReplacements()) { - llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace); - if (Err) { - llvm::errs() << "Renaming failed in " << Replace.getFilePath() - << "! " << llvm::toString(std::move(Err)) << "\n"; - } - } - } + convertChangesToFileReplacements(AtomicChanges, &FileToReplaces); } } diff --git a/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp new file mode 100644 index 00000000000..ea64b2c1aa8 --- /dev/null +++ b/clang/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp @@ -0,0 +1,37 @@ +//===--- SymbolOccurrences.cpp - Clang refactoring library ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; +using namespace tooling; + +SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, + ArrayRef<SourceLocation> Locations) + : 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())); + for (const auto &Loc : llvm::enumerate(Locations)) { + MultipleRanges[Loc.index()] = SourceRange( + Loc.value(), + Loc.value().getLocWithOffset(NamePieces[Loc.index()].size())); + } +} diff --git a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index dc21a94610c..43b03caa2ed 100644 --- a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -23,6 +23,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Tooling/Core/Lookup.h" #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" +#include "clang/Tooling/Refactoring/Rename/SymbolName.h" #include "clang/Tooling/Refactoring/Rename/USRFinder.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -68,11 +69,9 @@ public: // Non-visitors: - // \brief Returns a list of unique locations. Duplicate or overlapping - // locations are erroneous and should be reported! - const std::vector<clang::SourceLocation> &getLocationsFound() const { - return LocationsFound; - } + /// \brief Returns a set of unique symbol occurrences. Duplicate or + /// overlapping occurrences are erroneous and should be reported! + SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } private: void checkAndAddLocation(SourceLocation Loc) { @@ -82,17 +81,18 @@ private: StringRef TokenName = Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), Context.getSourceManager(), Context.getLangOpts()); - size_t Offset = TokenName.find(PrevName); + size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); // The token of the source location we find actually has the old // name. if (Offset != StringRef::npos) - LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); + Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, + BeginLoc.getLocWithOffset(Offset)); } const std::set<std::string> USRSet; - const std::string PrevName; - std::vector<clang::SourceLocation> LocationsFound; + const SymbolName PrevName; + SymbolOccurrences Occurrences; const ASTContext &Context; }; @@ -391,12 +391,11 @@ private: } // namespace -std::vector<SourceLocation> -getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName, - Decl *Decl) { +SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, + StringRef PrevName, Decl *Decl) { USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); Visitor.TraverseDecl(Decl); - return Visitor.getLocationsFound(); + return Visitor.takeOccurrences(); } std::vector<tooling::AtomicChange> |