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