Author: arphaman Date: Mon Aug 14 09:19:24 2017 New Revision: 310853 URL: http://llvm.org/viewvc/llvm-project?rev=310853&view=rev Log: [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 Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolName.h cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h cfe/trunk/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp Modified: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Modified: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h?rev=310853&r1=310852&r2=310853&view=diff ============================================================================== --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h (original) +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h Mon Aug 14 09:19:24 2017 @@ -16,6 +16,9 @@ #define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H #include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" +#include "llvm/Support/Error.h" namespace clang { class ASTConsumer; @@ -42,6 +45,13 @@ private: bool PrintLocations; }; +/// Returns source replacements that correspond to the rename of the given +/// symbol occurrences. +llvm::Expected<std::vector<AtomicChange>> +createRenameReplacements(const SymbolOccurrences &Occurrences, + const SourceManager &SM, + ArrayRef<StringRef> NewNameStrings); + /// Rename all symbols identified by the given USRs. class QualifiedRenamingAction { public: Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolName.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolName.h?rev=310853&view=auto ============================================================================== --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolName.h (added) +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolName.h Mon Aug 14 09:19:24 2017 @@ -0,0 +1,49 @@ +//===--- SymbolName.h - Clang refactoring library -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace tooling { + +/// A name of a symbol. +/// +/// Symbol's name can be composed of multiple strings. For example, Objective-C +/// methods can contain multiple argument lables: +/// +/// \code +/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y; +/// // ^~ string 0 ~~~~~ ^~ string 1 ~~~~~ +/// \endcode +class SymbolName { +public: + SymbolName(StringRef Name) { + // While empty symbol names are valid (Objective-C selectors can have empty + // name pieces), occurrences Objective-C selectors are created using an + // array of strings instead of just one string. + assert(!Name.empty() && "Invalid symbol name!"); + this->Name.push_back(Name.str()); + } + + ArrayRef<std::string> getNamePieces() const { return Name; } + +private: + llvm::SmallVector<std::string, 1> Name; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_NAME_H Added: cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h?rev=310853&view=auto ============================================================================== --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h (added) +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/SymbolOccurrences.h Mon Aug 14 09:19:24 2017 @@ -0,0 +1,91 @@ +//===--- SymbolOccurrences.h - Clang refactoring library ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H +#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { +namespace tooling { + +class SymbolName; + +/// An occurrence of a symbol in the source. +/// +/// Occurrences can have difference kinds, that describe whether this occurrence +/// is an exact semantic match, or whether this is a weaker textual match that's +/// not guaranteed to represent the exact declaration. +/// +/// A single occurrence of a symbol can span more than one source range. For +/// example, Objective-C selectors can contain multiple argument labels: +/// +/// \code +/// [object selectorPiece1: ... selectorPiece2: ...]; +/// // ^~~ range 0 ~~ ^~~ range 1 ~~ +/// \endcode +/// +/// We have to replace the text in both range 0 and range 1 when renaming the +/// Objective-C method 'selectorPiece1:selectorPiece2'. +class SymbolOccurrence { +public: + enum OccurrenceKind { + /// This occurrence is an exact match and can be renamed automatically. + /// + /// Note: + /// Symbol occurrences in macro arguments that expand to different + /// declarations get marked as exact matches, and thus the renaming engine + /// will rename them e.g.: + /// + /// \code + /// #define MACRO(x) x + ns::x + /// int foo(int var) { + /// return MACRO(var); // var is renamed automatically here when + /// // either var or ns::var is renamed. + /// }; + /// \endcode + /// + /// The user will have to fix their code manually after performing such a + /// rename. + /// FIXME: The rename verifier should notify user about this issue. + MatchingSymbol + }; + + SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind, + ArrayRef<SourceLocation> Locations); + + SymbolOccurrence(SymbolOccurrence &&) = default; + SymbolOccurrence &operator=(SymbolOccurrence &&) = default; + + OccurrenceKind getKind() const { return Kind; } + + ArrayRef<SourceRange> getNameRanges() const { + if (MultipleRanges) { + return llvm::makeArrayRef(MultipleRanges.get(), + RangeOrNumRanges.getBegin().getRawEncoding()); + } + return RangeOrNumRanges; + } + +private: + OccurrenceKind Kind; + std::unique_ptr<SourceRange[]> MultipleRanges; + SourceRange RangeOrNumRanges; +}; + +using SymbolOccurrences = std::vector<SymbolOccurrence>; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_SYMBOL_OCCURRENCES_H Modified: cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h?rev=310853&r1=310852&r2=310853&view=diff ============================================================================== --- cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h (original) +++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h Mon Aug 14 09:19:24 2017 @@ -19,6 +19,7 @@ #include "clang/AST/AST.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Refactoring/AtomicChange.h" +#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h" #include "llvm/ADT/StringRef.h" #include <string> #include <vector> @@ -38,10 +39,13 @@ std::vector<tooling::AtomicChange> createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, llvm::StringRef NewName, Decl *TranslationUnitDecl); -// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree! -std::vector<SourceLocation> -getLocationsOfUSRs(const std::vector<std::string> &USRs, - llvm::StringRef PrevName, Decl *Decl); +/// Finds the symbol occurrences for the symbol that's identified by the given +/// USR set. +/// +/// \return SymbolOccurrences that can be converted to AtomicChanges when +/// renaming. +SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, + StringRef PrevName, Decl *Decl); } // end namespace tooling } // end namespace clang Modified: cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt?rev=310853&r1=310852&r2=310853&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt (original) +++ cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt Mon Aug 14 09:19:24 2017 @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS Support) add_clang_library(clangToolingRefactor AtomicChange.cpp Rename/RenamingAction.cpp + Rename/SymbolOccurrences.cpp Rename/USRFinder.cpp Rename/USRFindingAction.cpp Rename/USRLocFinder.cpp Modified: cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp?rev=310853&r1=310852&r2=310853&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp (original) +++ cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp Mon Aug 14 09:19:24 2017 @@ -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); } } Added: cfe/trunk/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp?rev=310853&view=auto ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp (added) +++ cfe/trunk/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp Mon Aug 14 09:19:24 2017 @@ -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())); + } +} Modified: cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp?rev=310853&r1=310852&r2=310853&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp (original) +++ cfe/trunk/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Mon Aug 14 09:19:24 2017 @@ -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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits