vmiklos created this revision.
vmiklos added a reviewer: klimek.
vmiklos added a subscriber: cfe-commits.

This way parsing the source input multiple times for multiple renames can be 
avoided.

http://reviews.llvm.org/D21814

Files:
  clang-rename/RenamingAction.cpp
  clang-rename/RenamingAction.h
  clang-rename/tool/ClangRename.cpp
  test/clang-rename/ClassTestMulti.cpp
  test/clang-rename/ClassTestMultiByName.cpp

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
+};
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: 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 <cstdlib>
 #include <string>
+#include <sstream>
 
 using namespace llvm;
 
 cl::OptionCategory ClangRenameCategory("Clang-rename options");
 
 static cl::opt<std::string>
-NewName(
+NewNames(
     "new-name",
     cl::desc("The new name to change the symbol to."),
     cl::cat(ClangRenameCategory));
-static cl::opt<unsigned>
-SymbolOffset(
+static cl::opt<std::string>
+SymbolOffsets(
     "offset",
     cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
     cl::cat(ClangRenameCategory));
 static cl::opt<std::string>
-OldName(
+OldNames(
     "old-name",
     cl::desc("The fully qualified name of the symbol, if -offset is not used."),
     cl::cat(ClangRenameCategory));
@@ -91,39 +92,100 @@
 const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\
 clang-rename renames every occurrence of a symbol found at <offset> in\n\
 <source0>. 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);
   tooling::CommonOptionsParser OP(argc, argv, ClangRenameCategory, RenameUsage);
 
   // 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<std::string> NewNameList;
+  while (NewNameStream.good()) {
+    std::string Token;
+    std::getline(NewNameStream, Token, ',');
+    NewNameList.push_back(Token);
+  }
+
+  // Tokenize the offsets.
+  std::stringstream SymbolOffsetStream(SymbolOffsets);
+  std::vector<unsigned> 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<std::string> 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<std::vector<std::string>> USRList;
+  std::vector<std::string> 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: 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<std::string> &USRs,
+  RenamingAction(const std::vector<std::string> &NewNameList, const std::vector<std::string> &PrevNameList,
+                 const std::vector<std::vector<std::string>> &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<ASTConsumer> newASTConsumer();
 
 private:
-  const std::string &NewName, &PrevName;
-  const std::vector<std::string> &USRs;
+  const std::vector<std::string> &NewNameList, &PrevNameList;
+  const std::vector<std::vector<std::string>> &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<std::string> &USRs,
+  RenamingASTConsumer(const std::vector<std::string> &NewNameList,
+                      const std::vector<std::string> &PrevNameList,
+                      const std::vector<std::vector<std::string>> &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<std::string> &USRs) {
     const auto &SourceMgr = Context.getSourceManager();
     std::vector<SourceLocation> RenamingCandidates;
     std::vector<SourceLocation> NewCandidates;
@@ -72,14 +80,14 @@
   }
 
 private:
-  const std::string &NewName, &PrevName;
-  const std::vector<std::string> &USRs;
+  const std::vector<std::string> &NewNameList, &PrevNameList;
+  const std::vector<std::vector<std::string>> &USRList;
   tooling::Replacements &Replaces;
   bool PrintLocations;
 };
 
 std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
-  return llvm::make_unique<RenamingASTConsumer>(NewName, PrevName, USRs,
+  return llvm::make_unique<RenamingASTConsumer>(NewNameList, PrevNameList, USRList,
                                                 Replaces, PrintLocations);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to