blob: f50944b05afff01dad53099b5f573e38ac2d886d [file] [log] [blame]
Manuel Klimekde237262014-08-20 01:39:05 +00001//===--- 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
Manuel Klimek3f840a92014-10-13 11:30:27 +000016#include "../USRFindingAction.h"
17#include "../RenamingAction.h"
Manuel Klimekde237262014-08-20 01:39:05 +000018#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"
Manuel Klimekde237262014-08-20 01:39:05 +000028#include "clang/Lex/Lexer.h"
Chandler Carruth3cbd71c2015-01-14 11:24:38 +000029#include "clang/Lex/Preprocessor.h"
Manuel Klimekde237262014-08-20 01:39:05 +000030#include "clang/Parse/ParseAST.h"
Chandler Carruth3cbd71c2015-01-14 11:24:38 +000031#include "clang/Parse/Parser.h"
Manuel Klimekde237262014-08-20 01:39:05 +000032#include "clang/Rewrite/Core/Rewriter.h"
33#include "clang/Tooling/CommonOptionsParser.h"
34#include "clang/Tooling/Refactoring.h"
35#include "clang/Tooling/Tooling.h"
36#include "llvm/ADT/IntrusiveRefCntPtr.h"
37#include "llvm/Support/Host.h"
Eugene Zelenko05f7e6a2016-03-17 17:02:25 +000038#include <cstdlib>
Manuel Klimekde237262014-08-20 01:39:05 +000039#include <string>
Manuel Klimekde237262014-08-20 01:39:05 +000040
41using namespace llvm;
42
43cl::OptionCategory ClangRenameCategory("Clang-rename options");
44
45static cl::opt<std::string>
46NewName(
47 "new-name",
48 cl::desc("The new name to change the symbol to."),
49 cl::cat(ClangRenameCategory));
50static cl::opt<unsigned>
51SymbolOffset(
52 "offset",
53 cl::desc("Locates the symbol by offset as opposed to <line>:<column>."),
54 cl::cat(ClangRenameCategory));
55static cl::opt<bool>
56Inplace(
57 "i",
58 cl::desc("Overwrite edited <file>s."),
59 cl::cat(ClangRenameCategory));
60static cl::opt<bool>
61PrintName(
62 "pn",
63 cl::desc("Print the found symbol's name prior to renaming to stderr."),
64 cl::cat(ClangRenameCategory));
65static cl::opt<bool>
66PrintLocations(
67 "pl",
68 cl::desc("Print the locations affected by renaming to stderr."),
69 cl::cat(ClangRenameCategory));
70
71#define CLANG_RENAME_VERSION "0.0.1"
72
73static void PrintVersion() {
74 outs() << "clang-rename version " << CLANG_RENAME_VERSION << "\n";
75}
76
77using namespace clang;
78
79const char RenameUsage[] = "A tool to rename symbols in C/C++ code.\n\
80clang-rename renames every occurrence of a symbol found at <offset> in\n\
81<source0>. If -i is specified, the edited files are overwritten to disk.\n\
82Otherwise, the results are written to stdout.\n";
83
84int main(int argc, const char **argv) {
85 cl::SetVersionPrinter(PrintVersion);
86 tooling::CommonOptionsParser OP(argc, argv, ClangRenameCategory, RenameUsage);
87
88 // Check the arguments for correctness.
89
90 if (NewName.empty()) {
91 errs() << "clang-rename: no new name provided.\n\n";
92 cl::PrintHelpMessage();
93 exit(1);
94 }
95
96 // Get the USRs.
97 auto Files = OP.getSourcePathList();
98 tooling::RefactoringTool Tool(OP.getCompilations(), Files);
99 rename::USRFindingAction USRAction(SymbolOffset);
100
101 // Find the USRs.
102 Tool.run(tooling::newFrontendActionFactory(&USRAction).get());
103 const auto &USRs = USRAction.getUSRs();
104 const auto &PrevName = USRAction.getUSRSpelling();
105
106 if (PrevName.empty())
107 // An error should have already been printed.
108 exit(1);
109
110 if (PrintName)
111 errs() << "clang-rename: found name: " << PrevName;
112
113 // Perform the renaming.
114 rename::RenamingAction RenameAction(NewName, PrevName, USRs,
115 Tool.getReplacements(), PrintLocations);
116 auto Factory = tooling::newFrontendActionFactory(&RenameAction);
117 int res;
118
119 if (Inplace) {
120 res = Tool.runAndSave(Factory.get());
121 } else {
122 res = Tool.run(Factory.get());
123
124 // Write every file to stdout. Right now we just barf the files without any
125 // indication of which files start where, other than that we print the files
126 // in the same order we see them.
127 LangOptions DefaultLangOptions;
128 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
129 new DiagnosticOptions();
130 TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
131 DiagnosticsEngine Diagnostics(
132 IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
133 &*DiagOpts, &DiagnosticPrinter, false);
134 auto &FileMgr = Tool.getFiles();
135 SourceManager Sources(Diagnostics, FileMgr);
136 Rewriter Rewrite(Sources, DefaultLangOptions);
137
138 Tool.applyAllReplacements(Rewrite);
139 for (const auto &File : Files) {
140 const auto *Entry = FileMgr.getFile(File);
141 auto ID = Sources.translateFile(Entry);
142 Rewrite.getEditBuffer(ID).write(outs());
143 }
144 }
145
146 exit(res);
147}