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