clang-tools  3.9.0
ClangRename.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-rename/ClangRename.cpp - Clang rename tool -----===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements a clang-rename tool that automatically finds and
12 /// renames symbols in C++ code.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "../USRFindingAction.h"
17 #include "../RenamingAction.h"
18 #include "clang/AST/ASTConsumer.h"
19 #include "clang/AST/ASTContext.h"
20 #include "clang/Basic/FileManager.h"
21 #include "clang/Basic/LangOptions.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include "clang/Basic/TargetOptions.h"
24 #include "clang/Frontend/CommandLineSourceLoc.h"
25 #include "clang/Frontend/CompilerInstance.h"
26 #include "clang/Frontend/FrontendAction.h"
27 #include "clang/Frontend/TextDiagnosticPrinter.h"
28 #include "clang/Lex/Lexer.h"
29 #include "clang/Lex/Preprocessor.h"
30 #include "clang/Parse/ParseAST.h"
31 #include "clang/Parse/Parser.h"
32 #include "clang/Rewrite/Core/Rewriter.h"
33 #include "clang/Tooling/CommonOptionsParser.h"
34 #include "clang/Tooling/Refactoring.h"
35 #include "clang/Tooling/ReplacementsYaml.h"
36 #include "clang/Tooling/Tooling.h"
37 #include "llvm/ADT/IntrusiveRefCntPtr.h"
38 #include "llvm/Support/Host.h"
39 #include <string>
40 
41 using namespace llvm;
42 
43 cl::OptionCategory ClangRenameCategory("Clang-rename options");
44 
45 static cl::opt<std::string>
46 NewName(
47  "new-name",
48  cl::desc("The new name to change the symbol to."),
49  cl::cat(ClangRenameCategory));
50 static cl::opt<unsigned>
52  "offset",
53  cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
54  cl::cat(ClangRenameCategory));
55 static cl::opt<std::string>
56 OldName(
57  "old-name",
58  cl::desc("The fully qualified name of the symbol, if -offset is not used."),
59  cl::cat(ClangRenameCategory));
60 static cl::opt<bool>
61 Inplace(
62  "i",
63  cl::desc("Overwrite edited <file>s."),
64  cl::cat(ClangRenameCategory));
65 static cl::opt<bool>
66 PrintName(
67  "pn",
68  cl::desc("Print the found symbol's name prior to renaming to stderr."),
69  cl::cat(ClangRenameCategory));
70 static cl::opt<bool>
72  "pl",
73  cl::desc("Print the locations affected by renaming to stderr."),
74  cl::cat(ClangRenameCategory));
75 static cl::opt<std::string>
77  "export-fixes",
78  cl::desc("YAML file to store suggested fixes in."),
79  cl::value_desc("filename"),
80  cl::cat(ClangRenameCategory));
81 
82 #define CLANG_RENAME_VERSION "0.0.1"
83 
84 static void PrintVersion() {
85  outs() << "clang-rename version " << CLANG_RENAME_VERSION << '\n';
86 }
87 
88 using namespace clang;
89 
90 const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\
91 clang-rename renames every occurrence of a symbol found at <offset> in\n\
92 <source0>. If -i is specified, the edited files are overwritten to disk.\n\
93 Otherwise, the results are written to stdout.\n";
94 
95 int main(int argc, const char **argv) {
96  cl::SetVersionPrinter(PrintVersion);
97  tooling::CommonOptionsParser OP(argc, argv, ClangRenameCategory, RenameUsage);
98 
99  // Check the arguments for correctness.
100 
101  if (NewName.empty()) {
102  errs() << "clang-rename: no new name provided.\n\n";
103  exit(1);
104  }
105 
106  // Get the USRs.
107  auto Files = OP.getSourcePathList();
108  tooling::RefactoringTool Tool(OP.getCompilations(), Files);
110 
111  // Find the USRs.
112  Tool.run(tooling::newFrontendActionFactory(&USRAction).get());
113  const auto &USRs = USRAction.getUSRs();
114  const auto &PrevName = USRAction.getUSRSpelling();
115 
116  if (PrevName.empty()) {
117  // An error should have already been printed.
118  exit(1);
119  }
120 
121  if (PrintName) {
122  errs() << "clang-rename: found name: " << PrevName << '\n';
123  }
124 
125  // Perform the renaming.
126  rename::RenamingAction RenameAction(NewName, PrevName, USRs,
127  Tool.getReplacements(), PrintLocations);
128  auto Factory = tooling::newFrontendActionFactory(&RenameAction);
129  int ExitCode;
130 
131  if (Inplace) {
132  ExitCode = Tool.runAndSave(Factory.get());
133  } else {
134  ExitCode = Tool.run(Factory.get());
135 
136  if (!ExportFixes.empty()) {
137  std::error_code EC;
138  llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
139  if (EC) {
140  llvm::errs() << "Error opening output file: " << EC.message() << '\n';
141  exit(1);
142  }
143 
144  // Export replacements.
145  tooling::TranslationUnitReplacements TUR;
146  const tooling::Replacements &Replacements = Tool.getReplacements();
147  TUR.Replacements.insert(TUR.Replacements.end(), Replacements.begin(),
148  Replacements.end());
149 
150  yaml::Output YAML(OS);
151  YAML << TUR;
152  OS.close();
153  exit(0);
154  }
155 
156  // Write every file to stdout. Right now we just barf the files without any
157  // indication of which files start where, other than that we print the files
158  // in the same order we see them.
159  LangOptions DefaultLangOptions;
160  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
161  new DiagnosticOptions();
162  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
163  DiagnosticsEngine Diagnostics(
164  IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
165  &*DiagOpts, &DiagnosticPrinter, false);
166  auto &FileMgr = Tool.getFiles();
167  SourceManager Sources(Diagnostics, FileMgr);
168  Rewriter Rewrite(Sources, DefaultLangOptions);
169 
170  Tool.applyAllReplacements(Rewrite);
171  for (const auto &File : Files) {
172  const auto *Entry = FileMgr.getFile(File);
173  auto ID = Sources.translateFile(Entry);
174  Rewrite.getEditBuffer(ID).write(outs());
175  }
176  }
177 
178  exit(ExitCode);
179 }
static cl::opt< bool > PrintName("pn", cl::desc("Print the found symbol's name prior to renaming to stderr."), cl::cat(ClangRenameCategory))
HeaderHandle File
int main(int argc, const char **argv)
Definition: ClangRename.cpp:95
static cl::opt< bool > Inplace("i", cl::desc("Overwrite edited <file>s."), cl::cat(ClangRenameCategory))
Rewriter Rewrite
Definition: ClangTidy.cpp:194
static cl::opt< bool > PrintLocations("pl", cl::desc("Print the locations affected by renaming to stderr."), cl::cat(ClangRenameCategory))
#define CLANG_RENAME_VERSION
Definition: ClangRename.cpp:82
static cl::opt< std::string > ExportFixes("export-fixes", cl::desc("YAML file to store suggested fixes in."), cl::value_desc("filename"), cl::cat(ClangRenameCategory))
static cl::opt< std::string > NewName("new-name", cl::desc("The new name to change the symbol to."), cl::cat(ClangRenameCategory))
const std::string PrevName
static cl::opt< unsigned > SymbolOffset("offset", cl::desc("Locates the symbol by offset as opposed to <line>:<column>."), cl::cat(ClangRenameCategory))
const char RenameUsage[]
Definition: ClangRename.cpp:90
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 void PrintVersion()
Definition: ClangRename.cpp:84
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Definition: ClangTidy.cpp:190
FileManager Files
Definition: ClangTidy.cpp:188
cl::OptionCategory ClangRenameCategory("Clang-rename options")