summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-rename/ClangRename.cpp
blob: 077c591826b651fc72e8a1917b946dc9915369d9 (plain)
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
//===--- 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/Preprocessor.h"
#include "clang/Lex/Lexer.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/Host.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <string>
#include <vector>

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<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));

#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";
    cl::PrintHelpMessage();
    exit(1);
  }

  // Get the USRs.
  auto Files = OP.getSourcePathList();
  tooling::RefactoringTool Tool(OP.getCompilations(), Files);
  rename::USRFindingAction USRAction(SymbolOffset);

  // 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;

  // Perform the renaming.
  rename::RenamingAction RenameAction(NewName, PrevName, USRs,
                                      Tool.getReplacements(), PrintLocations);
  auto Factory = tooling::newFrontendActionFactory(&RenameAction);
  int res;

  if (Inplace) {
    res = Tool.runAndSave(Factory.get());
  } else {
    res = Tool.run(Factory.get());

    // 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(res);
}
OpenPOWER on IntegriCloud