Index: clang-tools-extra/trunk/clang-rename/USRFinder.h =================================================================== --- clang-tools-extra/trunk/clang-rename/USRFinder.h +++ clang-tools-extra/trunk/clang-rename/USRFinder.h @@ -30,6 +30,12 @@ const NamedDecl *getNamedDeclAt(const ASTContext &Context, const SourceLocation Point); +// Given an AST context and a fully qualified name, returns a NamedDecl +// identifying the symbol with a matching name. Returns null if nothing is +// found for the name. +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name); + // Converts a Decl into a USR. std::string getUSRForDecl(const Decl *Decl); Index: clang-tools-extra/trunk/clang-rename/USRFinder.cpp =================================================================== --- clang-tools-extra/trunk/clang-rename/USRFinder.cpp +++ clang-tools-extra/trunk/clang-rename/USRFinder.cpp @@ -40,6 +40,14 @@ Point(Point) { } + // \brief Finds the NamedDecl for a name in the source. + // \param Name the fully qualified name. + explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr, + const std::string &Name) + : Result(nullptr), SourceMgr(SourceMgr), + Name(Name) { + } + // Declaration visitors: // \brief Checks if the point falls within the NameDecl. This covers every @@ -93,9 +101,17 @@ // \returns false on success. bool setResult(const NamedDecl *Decl, SourceLocation Start, SourceLocation End) { - if (!Start.isValid() || !Start.isFileID() || !End.isValid() || - !End.isFileID() || !isPointWithin(Start, End)) { - return true; + if (Name.empty()) { + // Offset is used to find the declaration. + if (!Start.isValid() || !Start.isFileID() || !End.isValid() || + !End.isFileID() || !isPointWithin(Start, End)) { + return true; + } + } else { + // Fully qualified name is used to find the declaration. + if (Name != Decl->getQualifiedNameAsString()) { + return true; + } } Result = Decl; return false; @@ -121,6 +137,7 @@ const NamedDecl *Result; const SourceManager &SourceMgr; const SourceLocation Point; // The location to find the NamedDecl. + const std::string Name; }; } @@ -148,6 +165,22 @@ return nullptr; } +const NamedDecl *getNamedDeclFor(const ASTContext &Context, + const std::string &Name) { + const auto &SourceMgr = Context.getSourceManager(); + NamedDeclFindingASTVisitor Visitor(SourceMgr, Name); + auto Decls = Context.getTranslationUnitDecl()->decls(); + + for (auto &CurrDecl : Decls) { + Visitor.TraverseDecl(CurrDecl); + if (const NamedDecl *Result = Visitor.getNamedDecl()) { + return Result; + } + } + + return nullptr; +} + std::string getUSRForDecl(const Decl *Decl) { llvm::SmallVector Buff; Index: clang-tools-extra/trunk/clang-rename/USRFindingAction.h =================================================================== --- clang-tools-extra/trunk/clang-rename/USRFindingAction.h +++ clang-tools-extra/trunk/clang-rename/USRFindingAction.h @@ -25,7 +25,7 @@ namespace rename { struct USRFindingAction { - USRFindingAction(unsigned Offset) : SymbolOffset(Offset) { + USRFindingAction(unsigned Offset, const std::string &Name) : SymbolOffset(Offset), OldName(Name) { } std::unique_ptr newASTConsumer(); @@ -40,6 +40,7 @@ private: unsigned SymbolOffset; + std::string OldName; std::string SpellingName; std::vector USRs; }; Index: clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp =================================================================== --- clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp +++ clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp @@ -68,7 +68,12 @@ SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset); if (!Point.isValid()) return; - const NamedDecl *FoundDecl = getNamedDeclAt(Context, Point); + const NamedDecl *FoundDecl = nullptr; + if (OldName.empty()) { + FoundDecl = getNamedDeclAt(Context, Point); + } else { + FoundDecl = getNamedDeclFor(Context, OldName); + } if (FoundDecl == nullptr) { FullSourceLoc FullLoc(Point, SourceMgr); errs() << "clang-rename: could not find symbol at " @@ -96,6 +101,7 @@ } unsigned SymbolOffset; + std::string OldName; std::string *SpellingName; std::vector *USRs; }; @@ -106,6 +112,7 @@ new NamedDeclFindingConsumer); SpellingName = ""; Consumer->SymbolOffset = SymbolOffset; + Consumer->OldName = OldName; Consumer->USRs = &USRs; Consumer->SpellingName = &SpellingName; return std::move(Consumer); Index: clang-tools-extra/trunk/clang-rename/tool/ClangRename.cpp =================================================================== --- clang-tools-extra/trunk/clang-rename/tool/ClangRename.cpp +++ clang-tools-extra/trunk/clang-rename/tool/ClangRename.cpp @@ -52,6 +52,11 @@ "offset", cl::desc("Locates the symbol by offset as opposed to :."), cl::cat(ClangRenameCategory)); +static cl::opt +OldName( + "old-name", + cl::desc("The fully qualified name of the symbol, if -offset is not used."), + cl::cat(ClangRenameCategory)); static cl::opt Inplace( "i", @@ -96,7 +101,7 @@ // Get the USRs. auto Files = OP.getSourcePathList(); tooling::RefactoringTool Tool(OP.getCompilations(), Files); - rename::USRFindingAction USRAction(SymbolOffset); + rename::USRFindingAction USRAction(SymbolOffset, OldName); // Find the USRs. Tool.run(tooling::newFrontendActionFactory(&USRAction).get()); Index: clang-tools-extra/trunk/test/clang-rename/ClassTestByName.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-rename/ClassTestByName.cpp +++ clang-tools-extra/trunk/test/clang-rename/ClassTestByName.cpp @@ -0,0 +1,10 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -old-name=Cla -new-name=Hector %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s +class Cla { // CHECK: class Hector +}; + +int main() { + Cla *Pointer = 0; // CHECK: Hector *Pointer = 0; + return 0; +}