Index: clang-rename/RenamingAction.h =================================================================== --- clang-rename/RenamingAction.h +++ clang-rename/RenamingAction.h @@ -25,18 +25,18 @@ class RenamingAction { public: - RenamingAction(const std::string &NewName, const std::string &PrevName, - const std::vector &USRs, + RenamingAction(const std::vector &NewNameList, const std::vector &PrevNameList, + const std::vector> &USRList, tooling::Replacements &Replaces, bool PrintLocations = false) - : NewName(NewName), PrevName(PrevName), USRs(USRs), Replaces(Replaces), + : NewNameList(NewNameList), PrevNameList(PrevNameList), USRList(USRList), Replaces(Replaces), PrintLocations(PrintLocations) { } std::unique_ptr newASTConsumer(); private: - const std::string &NewName, &PrevName; - const std::vector &USRs; + const std::vector &NewNameList, &PrevNameList; + const std::vector> &USRList; tooling::Replacements &Replaces; bool PrintLocations; }; Index: clang-rename/RenamingAction.cpp =================================================================== --- clang-rename/RenamingAction.cpp +++ clang-rename/RenamingAction.cpp @@ -34,16 +34,24 @@ class RenamingASTConsumer : public ASTConsumer { public: - RenamingASTConsumer(const std::string &NewName, - const std::string &PrevName, - const std::vector &USRs, + RenamingASTConsumer(const std::vector &NewNameList, + const std::vector &PrevNameList, + const std::vector> &USRList, tooling::Replacements &Replaces, bool PrintLocations) - : NewName(NewName), PrevName(PrevName), USRs(USRs), Replaces(Replaces), + : NewNameList(NewNameList), PrevNameList(PrevNameList), USRList(USRList), Replaces(Replaces), PrintLocations(PrintLocations) { } void HandleTranslationUnit(ASTContext &Context) override { + for (unsigned I = 0; I < NewNameList.size(); ++I) { + HandleOneRename(Context, NewNameList[I], PrevNameList[I], USRList[I]); + } + } + + void HandleOneRename(ASTContext &Context, const std::string &NewName, + const std::string &PrevName, + const std::vector &USRs) { const auto &SourceMgr = Context.getSourceManager(); std::vector RenamingCandidates; std::vector NewCandidates; @@ -72,14 +80,14 @@ } private: - const std::string &NewName, &PrevName; - const std::vector &USRs; + const std::vector &NewNameList, &PrevNameList; + const std::vector> &USRList; tooling::Replacements &Replaces; bool PrintLocations; }; std::unique_ptr RenamingAction::newASTConsumer() { - return llvm::make_unique(NewName, PrevName, USRs, + return llvm::make_unique(NewNameList, PrevNameList, USRList, Replaces, PrintLocations); } Index: clang-rename/tool/ClangRename.cpp =================================================================== --- clang-rename/tool/ClangRename.cpp +++ clang-rename/tool/ClangRename.cpp @@ -38,23 +38,24 @@ #include "llvm/Support/Host.h" #include #include +#include using namespace llvm; cl::OptionCategory ClangRenameCategory("Clang-rename options"); static cl::opt -NewName( +NewNames( "new-name", cl::desc("The new name to change the symbol to."), cl::cat(ClangRenameCategory)); -static cl::opt -SymbolOffset( +static cl::opt +SymbolOffsets( "offset", cl::desc("Locates the symbol by offset as opposed to :."), cl::cat(ClangRenameCategory)); static cl::opt -OldName( +OldNames( "old-name", cl::desc("The fully qualified name of the symbol, if -offset is not used."), cl::cat(ClangRenameCategory)); @@ -91,7 +92,9 @@ const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\ clang-rename renames every occurrence of a symbol found at in\n\ . If -i is specified, the edited files are overwritten to disk.\n\ -Otherwise, the results are written to stdout.\n"; +Otherwise, the results are written to stdout.\n\ +-offset, -old-name and -new-name accept a comma-separated list to perform\n\ +multiple renames with one invocation.\n"; int main(int argc, const char **argv) { cl::SetVersionPrinter(PrintVersion); @@ -99,31 +102,90 @@ // Check the arguments for correctness. - if (NewName.empty()) { + if (NewNames.empty()) { errs() << "clang-rename: no new name provided.\n\n"; cl::PrintHelpMessage(); exit(1); } - // Get the USRs. - auto Files = OP.getSourcePathList(); - tooling::RefactoringTool Tool(OP.getCompilations(), Files); - rename::USRFindingAction USRAction(SymbolOffset, OldName); + // Tokenize the new names. + std::stringstream NewNameStream(NewNames); + std::vector NewNameList; + while (NewNameStream.good()) { + std::string Token; + std::getline(NewNameStream, Token, ','); + NewNameList.push_back(Token); + } + + // Tokenize the offsets. + std::stringstream SymbolOffsetStream(SymbolOffsets); + std::vector SymbolOffsetList; + while (SymbolOffsetStream.good()) { + std::string Token; + std::getline(SymbolOffsetStream, Token, ','); + if (Token.empty()) { + break; + } + SymbolOffsetList.push_back(std::stoi(Token)); + } + + if (!SymbolOffsetList.empty() && SymbolOffsetList.size() != NewNameList.size()) { + errs() << "clang-rename: number of offsets (" << SymbolOffsetList.size() << + ") do not equal to number of new names (" << NewNameList.size() << + ").\n\n"; + cl::PrintHelpMessage(); + exit(1); + } - // Find the USRs. - Tool.run(tooling::newFrontendActionFactory(&USRAction).get()); - const auto &USRs = USRAction.getUSRs(); - const auto &PrevName = USRAction.getUSRSpelling(); + // Tokenize the old names. + std::stringstream OldNameStream(OldNames); + std::vector OldNameList; + while (OldNameStream.good()) { + std::string Token; + std::getline(OldNameStream, Token, ','); + if (Token.empty()) { + break; + } + OldNameList.push_back(Token); + } - if (PrevName.empty()) - // An error should have already been printed. + if (!OldNameList.empty() && OldNameList.size() != NewNameList.size()) { + errs() << "clang-rename: number of old names (" << OldNameList.size() << + ") do not equal to number of new names (" << NewNameList.size() << + ").\n\n"; + cl::PrintHelpMessage(); exit(1); + } - if (PrintName) - errs() << "clang-rename: found name: " << PrevName << "\n"; + std::vector> USRList; + std::vector PrevNameList; + auto Files = OP.getSourcePathList(); + tooling::RefactoringTool Tool(OP.getCompilations(), Files); + unsigned Count = OldNameList.size() ? OldNameList.size() : SymbolOffsetList.size(); + for (unsigned I = 0; I < Count; ++I) { + unsigned SymbolOffset = SymbolOffsetList.empty() ? 0 : SymbolOffsetList[I]; + const std::string& OldName = OldNameList.empty() ? std::string() : OldNameList[I]; + + // Get the USRs. + rename::USRFindingAction USRAction(SymbolOffset, OldName); + + // Find the USRs. + Tool.run(tooling::newFrontendActionFactory(&USRAction).get()); + const auto &USRs = USRAction.getUSRs(); + USRList.push_back(USRs); + const auto &PrevName = USRAction.getUSRSpelling(); + PrevNameList.push_back(PrevName); + + if (PrevName.empty()) + // An error should have already been printed. + exit(1); + + if (PrintName) + errs() << "clang-rename: found name: " << PrevName << "\n"; + } // Perform the renaming. - rename::RenamingAction RenameAction(NewName, PrevName, USRs, + rename::RenamingAction RenameAction(NewNameList, PrevNameList, USRList, Tool.getReplacements(), PrintLocations); auto Factory = tooling::newFrontendActionFactory(&RenameAction); int res; Index: test/clang-rename/ClassTestMulti.cpp =================================================================== --- /dev/null +++ test/clang-rename/ClassTestMulti.cpp @@ -0,0 +1,8 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=145,183 -new-name=Kla1,Kla2 %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s +class Cla1 { // CHECK: class Kla1 +}; + +class Cla2 { // CHECK: class Kla2 +}; Index: test/clang-rename/ClassTestMultiByName.cpp =================================================================== --- /dev/null +++ test/clang-rename/ClassTestMultiByName.cpp @@ -0,0 +1,8 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -old-name=Cla1,Cla2 -new-name=Kla1,Kla2 %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s +class Cla1 { // CHECK: class Kla1 +}; + +class Cla2 { // CHECK: class Kla2 +};