clang-tools 8.0.0

ClangMoveMain.cpp
Go to the documentation of this file.
1 //===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
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 #include "ClangMove.h"
11 #include "clang/Frontend/TextDiagnosticPrinter.h"
12 #include "clang/Rewrite/Core/Rewriter.h"
13 #include "clang/Tooling/ArgumentsAdjusters.h"
14 #include "clang/Tooling/CommonOptionsParser.h"
15 #include "clang/Tooling/Refactoring.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Support/Process.h"
21 #include "llvm/Support/Signals.h"
22 #include "llvm/Support/YAMLTraits.h"
23 #include <set>
24 #include <string>
25
26 using namespace clang;
27 using namespace llvm;
28
29 namespace {
30
31 std::error_code CreateNewFile(const llvm::Twine &path) {
32 int fd = 0;
33 if (std::error_code ec = llvm::sys::fs::openFileForWrite(
34 path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
35 return ec;
36
37 return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
38 }
39
40 cl::OptionCategory ClangMoveCategory("clang-move options");
41
42 cl::list<std::string> Names("names", cl::CommaSeparated,
43 cl::desc("The list of the names of classes being "
44 "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
45 cl::cat(ClangMoveCategory));
46
47 cl::opt<std::string>
48 OldHeader("old_header",
49 cl::desc("The relative/absolute file path of old header."),
50 cl::cat(ClangMoveCategory));
51
52 cl::opt<std::string>
53 OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
54 cl::cat(ClangMoveCategory));
55
56 cl::opt<std::string>
57 NewHeader("new_header",
58 cl::desc("The relative/absolute file path of new header."),
59 cl::cat(ClangMoveCategory));
60
61 cl::opt<std::string>
62 NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
63 cl::cat(ClangMoveCategory));
64
65 cl::opt<bool>
66 OldDependOnNew("old_depend_on_new",
67 cl::desc("Whether old header will depend on new header. If "
68 "true, clang-move will "
69 "add #include of new header to old header."),
70 cl::init(false), cl::cat(ClangMoveCategory));
71
72 cl::opt<bool>
73 NewDependOnOld("new_depend_on_old",
74 cl::desc("Whether new header will depend on old header. If "
75 "true, clang-move will "
76 "add #include of old header to new header."),
77 cl::init(false), cl::cat(ClangMoveCategory));
78
79 cl::opt<std::string>
80 Style("style",
81 cl::desc("The style name used for reformatting. Default is \"llvm\""),
82 cl::init("llvm"), cl::cat(ClangMoveCategory));
83
84 cl::opt<bool> Dump("dump_result",
85 cl::desc("Dump results in JSON format to stdout."),
86 cl::cat(ClangMoveCategory));
87
88 cl::opt<bool> DumpDecls(
89 "dump_decls",
90 cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
91 "the option is specified, other command options will be ignored. "
92 "An empty JSON will be returned if old header isn't specified."),
93 cl::cat(ClangMoveCategory));
94
95 } // namespace
96
97 int main(int argc, const char **argv) {
98 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
99 tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
100
101 if (OldDependOnNew && NewDependOnOld) {
102 llvm::errs() << "Provide either --old_depend_on_new or "
103 "--new_depend_on_old. clang-move doesn't support these two "
104 "options at same time (It will introduce include cycle).\n";
105 return 1;
106 }
107
108 tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
109 OptionsParser.getSourcePathList());
110 // Add "-fparse-all-comments" compile option to make clang parse all comments.
111 Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
112 "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
113 move::MoveDefinitionSpec Spec;
114 Spec.Names = {Names.begin(), Names.end()};
115 Spec.OldHeader = OldHeader;
116 Spec.NewHeader = NewHeader;
117 Spec.OldCC = OldCC;
118 Spec.NewCC = NewCC;
119 Spec.OldDependOnNew = OldDependOnNew;
120 Spec.NewDependOnOld = NewDependOnOld;
121
122 llvm::SmallString<128> InitialDirectory;
123 if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
124 llvm::report_fatal_error("Cannot detect current path: " +
125 Twine(EC.message()));
126
127 move::ClangMoveContext Context{Spec, Tool.getReplacements(),
128 InitialDirectory.str(), Style, DumpDecls};
129 move::DeclarationReporter Reporter;
130 move::ClangMoveActionFactory Factory(&Context, &Reporter);
131
132 int CodeStatus = Tool.run(&Factory);
133 if (CodeStatus)
134 return CodeStatus;
135
136 if (DumpDecls) {
137 llvm::outs() << "[\n";
138 const auto &Declarations = Reporter.getDeclarationList();
139 for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
140 llvm::outs() << " {\n";
141 llvm::outs() << " \"DeclarationName\": \"" << I->QualifiedName
142 << "\",\n";
143 llvm::outs() << " \"DeclarationType\": \"" << I->Kind << "\",\n";
144 llvm::outs() << " \"Templated\": " << (I->Templated ? "true" : "false")
145 << "\n";
146 llvm::outs() << " }";
147 // Don't print trailing "," at the end of last element.
148 if (I != std::prev(E))
149 llvm::outs() << ",\n";
150 }
151 llvm::outs() << "\n]\n";
152 return 0;
153 }
154
155 if (!NewCC.empty()) {
156 std::error_code EC = CreateNewFile(NewCC);
157 if (EC) {
158 llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
159 << "\n";
160 return EC.value();
161 }
162 }
163 if (!NewHeader.empty()) {
164 std::error_code EC = CreateNewFile(NewHeader);
165 if (EC) {
166 llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
167 << "\n";
168 return EC.value();
169 }
170 }
171
172 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
173 clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
174 DiagnosticsEngine Diagnostics(
175 IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
176 &DiagnosticPrinter, false);
177 auto &FileMgr = Tool.getFiles();
178 SourceManager SM(Diagnostics, FileMgr);
179 Rewriter Rewrite(SM, LangOptions());
180
181 if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
182 llvm::errs() << "Failed applying all replacements.\n";
183 return 1;
184 }
185
186 if (Dump) {
187 std::set<llvm::StringRef> Files;
188 for (const auto &it : Tool.getReplacements())
189 Files.insert(it.first);
190 auto WriteToJson = [&](llvm::raw_ostream &OS) {
191 OS << "[\n";
192 for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
193 OS << " {\n";
194 OS << " \"FilePath\": \"" << *I << "\",\n";
195 const auto *Entry = FileMgr.getFile(*I);
196 auto ID = SM.translateFile(Entry);
197 std::string Content;
198 llvm::raw_string_ostream ContentStream(Content);
199 Rewrite.getEditBuffer(ID).write(ContentStream);
200 OS << " \"SourceText\": \""
201 << llvm::yaml::escape(ContentStream.str()) << "\"\n";
202 OS << " }";
203 if (I != std::prev(E))
204 OS << ",\n";
205 }
206 OS << "\n]\n";
207 };
208 WriteToJson(llvm::outs());
209 return 0;
210 }
211
212 return Rewrite.overwriteChangedFiles();
213 }
clang::move::ClangMoveContext
Definition: ClangMove.h:83
clang::move::MoveDefinitionSpec::OldHeader
std::string OldHeader
Definition: ClangMove.h:67
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
clang::move::MoveDefinitionSpec::NewHeader
std::string NewHeader
Definition: ClangMove.h:71
clang::move::MoveDefinitionSpec::Names
SmallVector< std::string, 4 > Names
Definition: ClangMove.h:65
clang::move::MoveDefinitionSpec::NewCC
std::string NewCC
Definition: ClangMove.h:73
ClangMove.h
clang::move::DeclarationReporter
Definition: ClangMove.h:30
clang::move::ClangMoveActionFactory
Definition: ClangMove.h:222
clang::move::DeclarationReporter::getDeclarationList
const std::vector< Declaration > getDeclarationList() const
Definition: ClangMove.h:53
main
int main(int argc, const char **argv)
Definition: ClangMoveMain.cpp:97
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::move::MoveDefinitionSpec::NewDependOnOld
bool NewDependOnOld
Definition: ClangMove.h:79
clang::move::MoveDefinitionSpec
Definition: ClangMove.h:63
clang::move::MoveDefinitionSpec::OldCC
std::string OldCC
Definition: ClangMove.h:69
clang::move::MoveDefinitionSpec::OldDependOnNew
bool OldDependOnNew
Definition: ClangMove.h:76
Entry
Definition: Modularize.cpp:430