vmiklos updated this revision to Diff 64941.

https://reviews.llvm.org/D21814

Files:
  clang-rename/RenamingAction.cpp
  clang-rename/RenamingAction.h
  clang-rename/tool/ClangRename.cpp
  clang-rename/tool/clang-rename.py
  docs/clang-rename.rst
  test/clang-rename/ClassFindByName.cpp
  test/clang-rename/ClassReplacements.cpp
  test/clang-rename/ClassSimpleRenaming.cpp
  test/clang-rename/ClassTestMulti.cpp
  test/clang-rename/ClassTestMultiByName.cpp
  test/clang-rename/ConstCastExpr.cpp
  test/clang-rename/ConstructExpr.cpp
  test/clang-rename/CtorFindByDeclaration.cpp
  test/clang-rename/CtorFindByDefinition.cpp
  test/clang-rename/CtorInitializer.cpp
  test/clang-rename/DeclRefExpr.cpp
  test/clang-rename/DtorDeclaration.cpp
  test/clang-rename/DtorDefinition.cpp
  test/clang-rename/DynamicCastExpr.cpp
  test/clang-rename/Field.cpp
  test/clang-rename/FunctionMacro.cpp
  test/clang-rename/InvalidNewName.cpp
  test/clang-rename/MemberExprMacro.cpp
  test/clang-rename/Namespace.cpp
  test/clang-rename/NoNewName.cpp
  test/clang-rename/ReinterpretCastExpr.cpp
  test/clang-rename/StaticCastExpr.cpp
  test/clang-rename/Variable.cpp
  test/clang-rename/VariableMacro.cpp

Index: test/clang-rename/VariableMacro.cpp
===================================================================
--- test/clang-rename/VariableMacro.cpp
+++ test/clang-rename/VariableMacro.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=208 -new-name=Z %t.cpp -i --
+// RUN: clang-rename rename-at -offset=218 -new-name=Z %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 #define Y X // CHECK: #define Y Z
Index: test/clang-rename/Variable.cpp
===================================================================
--- test/clang-rename/Variable.cpp
+++ test/clang-rename/Variable.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=148 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=158 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 namespace A {
Index: test/clang-rename/StaticCastExpr.cpp
===================================================================
--- test/clang-rename/StaticCastExpr.cpp
+++ test/clang-rename/StaticCastExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=152 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=162 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Baz {
Index: test/clang-rename/ReinterpretCastExpr.cpp
===================================================================
--- test/clang-rename/ReinterpretCastExpr.cpp
+++ test/clang-rename/ReinterpretCastExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=133 -new-name=X %t.cpp -i --
+// RUN: clang-rename rename-at -offset=143 -new-name=X %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 class Cla {
 public:
Index: test/clang-rename/NoNewName.cpp
===================================================================
--- test/clang-rename/NoNewName.cpp
+++ test/clang-rename/NoNewName.cpp
@@ -1,4 +1,4 @@
 // Check for an error while -new-name argument has not been passed to
 // clang-rename.
-// RUN: not clang-rename -offset=133 %s 2>&1 | FileCheck %s
-// CHECK: ERROR: no new name provided.
+// RUN: not clang-rename rename-at -offset=133 %s 2>&1 | FileCheck %s
+// CHECK: clang-rename rename-at: for the -new-name option: must be specified
Index: test/clang-rename/Namespace.cpp
===================================================================
--- test/clang-rename/Namespace.cpp
+++ test/clang-rename/Namespace.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=143 -new-name=llvm %t.cpp -i --
+// RUN: clang-rename rename-at -offset=153 -new-name=llvm %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 namespace foo { // CHECK: namespace llvm {
Index: test/clang-rename/MemberExprMacro.cpp
===================================================================
--- test/clang-rename/MemberExprMacro.cpp
+++ test/clang-rename/MemberExprMacro.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=156 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=166 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Baz {
Index: test/clang-rename/InvalidNewName.cpp
===================================================================
--- test/clang-rename/InvalidNewName.cpp
+++ test/clang-rename/InvalidNewName.cpp
@@ -1,2 +1,2 @@
-// RUN: not clang-rename -new-name=class -offset=133 %s 2>&1 | FileCheck %s
+// RUN: not clang-rename rename-at -new-name=class -offset=133 %s 2>&1 | FileCheck %s
 // CHECK: ERROR: new name is not a valid identifier in  C++17.
Index: test/clang-rename/FunctionMacro.cpp
===================================================================
--- test/clang-rename/FunctionMacro.cpp
+++ test/clang-rename/FunctionMacro.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=199 -new-name=macro_function %t.cpp -i --
+// RUN: clang-rename rename-at -offset=209 -new-name=macro_function %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 #define moo foo // CHECK: #define moo macro_function
Index: test/clang-rename/Field.cpp
===================================================================
--- test/clang-rename/Field.cpp
+++ test/clang-rename/Field.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=148 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=158 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Baz {
Index: test/clang-rename/DynamicCastExpr.cpp
===================================================================
--- test/clang-rename/DynamicCastExpr.cpp
+++ test/clang-rename/DynamicCastExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=195 -new-name=Bar %t.cpp -i -- -frtti
+// RUN: clang-rename rename-at -offset=205 -new-name=Bar %t.cpp -i -- -frtti
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Baz {
Index: test/clang-rename/DtorDefinition.cpp
===================================================================
--- test/clang-rename/DtorDefinition.cpp
+++ test/clang-rename/DtorDefinition.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=219 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=229 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {     // CHECK: class Bar {
Index: test/clang-rename/DtorDeclaration.cpp
===================================================================
--- test/clang-rename/DtorDeclaration.cpp
+++ test/clang-rename/DtorDeclaration.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=175 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=185 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo { // CHECK: class Bar {
Index: test/clang-rename/DeclRefExpr.cpp
===================================================================
--- test/clang-rename/DeclRefExpr.cpp
+++ test/clang-rename/DeclRefExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=161 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=171 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class C {
Index: test/clang-rename/CtorInitializer.cpp
===================================================================
--- test/clang-rename/CtorInitializer.cpp
+++ test/clang-rename/CtorInitializer.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=163 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=173 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Baz {};
Index: test/clang-rename/CtorFindByDefinition.cpp
===================================================================
--- test/clang-rename/CtorFindByDefinition.cpp
+++ test/clang-rename/CtorFindByDefinition.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=212 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=222 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {   // CHECK: class Bar
Index: test/clang-rename/CtorFindByDeclaration.cpp
===================================================================
--- test/clang-rename/CtorFindByDeclaration.cpp
+++ test/clang-rename/CtorFindByDeclaration.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=174 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=184 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {   // CHECK: class Bar
Index: test/clang-rename/ConstructExpr.cpp
===================================================================
--- test/clang-rename/ConstructExpr.cpp
+++ test/clang-rename/ConstructExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=136 -new-name=Boo %t.cpp -i --
+// RUN: clang-rename rename-at -offset=146 -new-name=Boo %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {};         // CHECK: class Boo {};
Index: test/clang-rename/ConstCastExpr.cpp
===================================================================
--- test/clang-rename/ConstCastExpr.cpp
+++ test/clang-rename/ConstCastExpr.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=146 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {                         // CHECK: class Bar {
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 rename-all -old-name=Cla1 -new-name=Kla1 -old-name=Cla2 -new-name=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 rename-all -offset=174 -new-name=Kla1 -offset=212 -new-name=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/ClassSimpleRenaming.cpp
===================================================================
--- test/clang-rename/ClassSimpleRenaming.cpp
+++ test/clang-rename/ClassSimpleRenaming.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-at -offset=146 -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {};       // CHECK: class Bar
Index: test/clang-rename/ClassReplacements.cpp
===================================================================
--- test/clang-rename/ClassReplacements.cpp
+++ test/clang-rename/ClassReplacements.cpp
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
 // RUN: mkdir -p %t/fixes
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -offset=254 -new-name=Bar -export-fixes=%t/fixes/clang-rename.yaml %t.cpp --
+// RUN: clang-rename rename-at -offset=264 -new-name=Bar -export-fixes=%t/fixes/clang-rename.yaml %t.cpp --
 // RUN: clang-apply-replacements %t
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
Index: test/clang-rename/ClassFindByName.cpp
===================================================================
--- test/clang-rename/ClassFindByName.cpp
+++ test/clang-rename/ClassFindByName.cpp
@@ -1,5 +1,5 @@
 // RUN: cat %s > %t.cpp
-// RUN: clang-rename -old-name=Foo -new-name=Bar %t.cpp -i --
+// RUN: clang-rename rename-all -old-name=Foo -new-name=Bar %t.cpp -i --
 // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
 
 class Foo {         // CHECK: class Bar
Index: docs/clang-rename.rst
===================================================================
--- docs/clang-rename.rst
+++ docs/clang-rename.rst
@@ -32,7 +32,7 @@
 
 .. code-block:: console
 
-  $ clang-rename -offset=42 -new-name=foo test.cpp -- -Imy_project/include -DMY_DEFINES ...
+  $ clang-rename rename-at -offset=42 -new-name=foo test.cpp -- -Imy_project/include -DMY_DEFINES ...
 
 
 To get an offset of a symbol in a file run
@@ -42,6 +42,14 @@
   $ grep -FUbo 'foo' file.cpp
 
 
+You can also identify one or more symbols to be renamed by giving the fully qualified
+name:
+
+.. code-block:: console
+
+  $ clang-rename rename-all -old-name=foo -new-name=bar test.cpp
+
+
 The tool currently supports renaming actions inside a single Translation Unit
 only. It is planned to extend the tool's functionality to support multi-TU
 renaming actions in the future.
@@ -55,34 +63,73 @@
 .. code-block:: console
 
   $ clang-rename -help
+  Usage: clang-rename {rename-at|rename-all} [OPTION]...
+
+  A tool to rename symbols in C/C++ code.
+
+  Subcommands:
+    rename-at:  Perform rename off of a location in a file.
+    rename-all: Perform rename of all symbols matching one or more fully qualified names.
+
+
+.. code-block:: console
+
+  $ clang-rename rename-at -help
   OVERVIEW: A tool to rename symbols in C/C++ code.
   clang-rename renames every occurrence of a symbol found at <offset> in
   <source0>. If -i is specified, the edited files are overwritten to disk.
   Otherwise, the results are written to stdout.
-
-  USAGE: clang-rename [subcommand] [options] <source0> [... <sourceN>]
-
+  
+  USAGE: clang-rename rename-at [subcommand] [options] <source0> [... <sourceN>]
+  
   OPTIONS:
+  
+  Generic Options:
+  
+    -help                      - Display available options (-help-hidden for more)
+    -help-list                 - Display list of available options (-help-list-hidden for more)
+    -version                   - Display the version of this program
 
-  Clang-rename options:
+  clang-rename rename-at options:
 
     -export-fixes=<filename>   - YAML file to store suggested fixes in.
     -extra-arg=<string>        - Additional argument to append to the compiler command line
     -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
     -i                         - Overwrite edited <file>s.
     -new-name=<string>         - The new name to change the symbol to.
     -offset=<uint>             - Locates the symbol by offset as opposed to <line>:<column>.
-    -old-name=<string>         - The fully qualified name of the symbol, if -offset is not used.
     -p=<string>                - Build path
     -pl                        - Print the locations affected by renaming to stderr.
     -pn                        - Print the found symbol's name prior to renaming to stderr.
 
+
+.. code-block:: console
+
+  $ ~/git/llvm/workdir/bin/clang-rename rename-all -help
+  OVERVIEW: A tool to rename symbols in C/C++ code.
+  clang-rename renames every occurrence of a symbol named <old-name>.
+
+  USAGE: clang-rename rename-all [subcommand] [options] <source0> [... <sourceN>]
+
+  OPTIONS:
+
   Generic Options:
 
     -help                      - Display available options (-help-hidden for more)
     -help-list                 - Display list of available options (-help-list-hidden for more)
     -version                   - Display the version of this program
 
+  clang-rename rename-all options:
+
+    -export-fixes=<filename>   - YAML file to store suggested fixes in.
+    -extra-arg=<string>        - Additional argument to append to the compiler command line
+    -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+    -i                         - Overwrite edited <file>s.
+    -new-name=<string>         - The new name to change the symbol to.
+    -offset=<uint>             - Locates the symbol by offset as opposed to <line>:<column>.
+    -old-name=<string>         - The fully qualified name of the symbol, if -offset is not used.
+    -p=<string>                - Build path
+
 
 clang-rename Vim integration
 ============================
Index: clang-rename/tool/clang-rename.py
===================================================================
--- clang-rename/tool/clang-rename.py
+++ clang-rename/tool/clang-rename.py
@@ -40,6 +40,7 @@
 
     # Call clang-rename.
     command = [binary,
+               "rename-at",
                filename,
                '-i',
                '-offset', str(offset),
Index: clang-rename/tool/ClangRename.cpp
===================================================================
--- clang-rename/tool/ClangRename.cpp
+++ clang-rename/tool/ClangRename.cpp
@@ -40,44 +40,8 @@
 
 using namespace llvm;
 
-cl::OptionCategory ClangRenameCategory("Clang-rename options");
-
-static cl::opt<std::string>
-NewName(
-    "new-name",
-    cl::desc("The new name to change the symbol to."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<unsigned>
-SymbolOffset(
-    "offset",
-    cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<std::string>
-OldName(
-    "old-name",
-    cl::desc("The fully qualified name of the symbol, if -offset is not used."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<bool>
-Inplace(
-    "i",
-    cl::desc("Overwrite edited <file>s."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<bool>
-PrintName(
-    "pn",
-    cl::desc("Print the found symbol's name prior to renaming to stderr."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<bool>
-PrintLocations(
-    "pl",
-    cl::desc("Print the locations affected by renaming to stderr."),
-    cl::cat(ClangRenameCategory));
-static cl::opt<std::string>
-ExportFixes(
-    "export-fixes",
-    cl::desc("YAML file to store suggested fixes in."),
-    cl::value_desc("filename"),
-    cl::cat(ClangRenameCategory));
+cl::OptionCategory ClangRenameAtCategory("clang-rename rename-at options");
+cl::OptionCategory ClangRenameAllCategory("clang-rename rename-all options");
 
 #define CLANG_RENAME_VERSION "0.0.1"
 
@@ -87,54 +51,134 @@
 
 using namespace clang;
 
-const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\
+const char RenameAtUsage[] = "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";
 
-int main(int argc, const char **argv) {
-  cl::SetVersionPrinter(PrintVersion);
-  tooling::CommonOptionsParser OP(argc, argv, ClangRenameCategory, RenameUsage);
+const char RenameAllUsage[] = "A tool to rename symbols in C/C++ code.\n\
+clang-rename renames every occurrence of a symbol named <old-name>.\n";
+
+enum RenameSubcommand {
+  RenameAt, RenameAll
+};
+
+int subcommandMain(RenameSubcommand Subcommand, int argc, const char **argv) {
+  cl::OptionCategory *Category = nullptr;
+  const char *Usage = nullptr;
+  if (Subcommand == RenameAt) {
+    Category = &ClangRenameAtCategory;
+    Usage = RenameAtUsage;
+  } else {
+    assert(Subcommand == RenameAll);
+    Category = &ClangRenameAllCategory;
+    Usage = RenameAllUsage;
+  }
+
+  cl::list<std::string>
+  NewNames(
+      "new-name",
+      cl::desc("The new name to change the symbol to."),
+      (Subcommand == RenameAt ? cl::Required : cl::OneOrMore),
+      cl::cat(*Category));
+  cl::list<unsigned>
+  SymbolOffsets(
+      "offset",
+      cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
+      (Subcommand == RenameAt ? cl::Required : cl::ZeroOrMore),
+      cl::cat(*Category));
+  cl::list<std::string>
+  OldNames(
+      "old-name",
+      cl::desc("The fully qualified name of the symbol, if -offset is not used."),
+      (Subcommand == RenameAt ? cl::Optional : cl::ZeroOrMore),
+      cl::cat(ClangRenameAllCategory));
+  cl::opt<bool>
+  Inplace(
+      "i",
+      cl::desc("Overwrite edited <file>s."),
+      cl::cat(*Category));
+  cl::opt<bool>
+  PrintName(
+      "pn",
+      cl::desc("Print the found symbol's name prior to renaming to stderr."),
+      cl::cat(ClangRenameAtCategory));
+  cl::opt<bool>
+  PrintLocations(
+      "pl",
+      cl::desc("Print the locations affected by renaming to stderr."),
+      cl::cat(ClangRenameAtCategory));
+  cl::opt<std::string>
+  ExportFixes(
+      "export-fixes",
+      cl::desc("YAML file to store suggested fixes in."),
+      cl::value_desc("filename"),
+      cl::cat(*Category));
+
+  tooling::CommonOptionsParser OP(argc, argv, *Category, Usage);
 
   // Check the arguments for correctness.
 
-  if (NewName.empty()) {
-    errs() << "ERROR: no new name provided.\n\n";
+  // Check if NewNames is a valid identifier in C++17.
+  for (const auto& NewName : NewNames) {
+    LangOptions Options;
+    Options.CPlusPlus = true;
+    Options.CPlusPlus1z = true;
+    IdentifierTable Table(Options);
+    auto NewNameTokKind = Table.get(NewName).getTokenID();
+    if (!tok::isAnyIdentifier(NewNameTokKind)) {
+      errs() << "ERROR: new name is not a valid identifier in  C++17.\n\n";
+      exit(1);
+    }
+  }
+
+  if (!OldNames.empty() && OldNames.size() != NewNames.size()) {
+    errs() << "clang-rename: number of old names (" << OldNames.size() <<
+      ") do not equal to number of new names (" << NewNames.size() <<
+      ").\n\n";
+    cl::PrintHelpMessage();
     exit(1);
   }
 
-  // Check if NewName is a valid identifier in C++17.
-  LangOptions Options;
-  Options.CPlusPlus = true;
-  Options.CPlusPlus1z = true;
-  IdentifierTable Table(Options);
-  auto NewNameTokKind = Table.get(NewName).getTokenID();
-  if (!tok::isAnyIdentifier(NewNameTokKind)) {
-    errs() << "ERROR: new name is not a valid identifier in  C++17.\n\n";
+  if (!SymbolOffsets.empty() && SymbolOffsets.size() != NewNames.size()) {
+    errs() << "clang-rename: number of symbol offsets (" << SymbolOffsets.size() <<
+      ") do not equal to number of new names (" << NewNames.size() <<
+      ").\n\n";
+    cl::PrintHelpMessage();
     exit(1);
   }
 
-  // Get the USRs.
+  std::vector<std::vector<std::string>> USRList;
+  std::vector<std::string> PrevNameList;
   auto Files = OP.getSourcePathList();
   tooling::RefactoringTool Tool(OP.getCompilations(), Files);
-  rename::USRFindingAction USRAction(SymbolOffset, OldName);
+  unsigned Count = OldNames.size() ? OldNames.size() : SymbolOffsets.size();
+  for (unsigned I = 0; I < Count; ++I) {
+    unsigned SymbolOffset = SymbolOffsets.empty() ? 0 : SymbolOffsets[I];
+    const std::string& OldName = OldNames.empty() ? std::string() : OldNames[I];
 
-  // Find the USRs.
-  Tool.run(tooling::newFrontendActionFactory(&USRAction).get());
-  const auto &USRs = USRAction.getUSRs();
-  const auto &PrevName = USRAction.getUSRSpelling();
+    // Get the USRs.
+    rename::USRFindingAction USRAction(SymbolOffset, OldName);
 
-  if (PrevName.empty()) {
-    // An error should have already been printed.
-    exit(1);
-  }
+    // 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 (PrintName) {
-    errs() << "clang-rename: found name: " << PrevName << '\n';
+    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(NewNames, PrevNameList, USRList,
                                       Tool.getReplacements(), PrintLocations);
   auto Factory = tooling::newFrontendActionFactory(&RenameAction);
   int ExitCode;
@@ -188,3 +232,52 @@
 
   exit(ExitCode);
 }
+
+/// \brief Top level help.
+static int helpMain(int argc, const char *argv[]) {
+  errs() << "Usage: clang-rename {rename-at|rename-all} [OPTION]...\n\n"
+         << "A tool to rename symbols in C/C++ code.\n\n"
+         << "Subcommands:\n"
+         << "  rename-at:  Perform rename off of a location in a file.\n"
+         << "  rename-all: Perform rename of all symbols matching one or more fully qualified names.\n";
+  return 0;
+}
+
+/// \brief Top level version information.
+static int versionMain(int argc, const char *argv[]) {
+  cl::PrintVersionMessage();
+  return 0;
+}
+
+static int renameAtMain(int argc, const char *argv[]) {
+  return subcommandMain(RenameAt, argc, argv);
+}
+static int renameAllMain(int argc, const char *argv[]) {
+  return subcommandMain(RenameAll, argc, argv);
+}
+
+int main(int argc, const char **argv) {
+  cl::SetVersionPrinter(PrintVersion);
+
+  if (argc > 1) {
+    using MainFunction = std::function<int(int, const char *[])>;
+    MainFunction Func = StringSwitch<MainFunction>(argv[1])
+      .Case("rename-at", renameAtMain)
+      .Case("rename-all", renameAllMain)
+      .Cases("-help", "--help", helpMain)
+      .Cases("-version", "--version", versionMain)
+      .Default(nullptr);
+
+    if (Func) {
+      std::string Invocation = std::string(argv[0]) + " " + argv[1];
+      argv[1] = Invocation.c_str();
+      return Func(argc - 1, argv + 1);
+    }
+  }
+
+  if (argc > 1) {
+    errs() << "clang-rename: unrecognized command: " << argv[1] << '\n';
+  }
+  helpMain(argc, argv);
+  return 1;
+}
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;
@@ -73,14 +81,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