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" 26 using namespace clang;
31 std::error_code CreateNewFile(
const llvm::Twine &path) {
33 if (std::error_code ec = llvm::sys::fs::openFileForWrite(
34 path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
37 return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
40 cl::OptionCategory ClangMoveCategory(
"clang-move options");
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));
48 OldHeader(
"old_header",
49 cl::desc(
"The relative/absolute file path of old header."),
50 cl::cat(ClangMoveCategory));
53 OldCC(
"old_cc", cl::desc(
"The relative/absolute file path of old cc."),
54 cl::cat(ClangMoveCategory));
57 NewHeader(
"new_header",
58 cl::desc(
"The relative/absolute file path of new header."),
59 cl::cat(ClangMoveCategory));
62 NewCC(
"new_cc", cl::desc(
"The relative/absolute file path of new cc."),
63 cl::cat(ClangMoveCategory));
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));
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));
81 cl::desc(
"The style name used for reformatting. Default is \"llvm\""),
82 cl::init(
"llvm"), cl::cat(ClangMoveCategory));
84 cl::opt<bool> Dump(
"dump_result",
85 cl::desc(
"Dump results in JSON format to stdout."),
86 cl::cat(ClangMoveCategory));
88 cl::opt<bool> DumpDecls(
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));
97 int main(
int argc,
const char **argv) {
98 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
99 tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
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";
108 tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
109 OptionsParser.getSourcePathList());
111 Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
112 "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
114 Spec.
Names = {Names.begin(), Names.end()};
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()));
128 InitialDirectory.str(), Style, DumpDecls};
132 int CodeStatus = Tool.run(&Factory);
137 llvm::outs() <<
"[\n";
139 for (
auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
140 llvm::outs() <<
" {\n";
141 llvm::outs() <<
" \"DeclarationName\": \"" << I->first <<
"\",\n";
142 llvm::outs() <<
" \"DeclarationType\": \"" << I->second <<
"\"\n";
143 llvm::outs() <<
" }";
145 if (I != std::prev(E))
146 llvm::outs() <<
",\n";
148 llvm::outs() <<
"\n]\n";
152 if (!NewCC.empty()) {
153 std::error_code EC = CreateNewFile(NewCC);
155 llvm::errs() <<
"Failed to create " << NewCC <<
": " << EC.message()
160 if (!NewHeader.empty()) {
161 std::error_code EC = CreateNewFile(NewHeader);
163 llvm::errs() <<
"Failed to create " << NewHeader <<
": " << EC.message()
169 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
new DiagnosticOptions());
170 clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
171 DiagnosticsEngine Diagnostics(
172 IntrusiveRefCntPtr<DiagnosticIDs>(
new DiagnosticIDs()), &*DiagOpts,
173 &DiagnosticPrinter,
false);
174 auto &FileMgr = Tool.getFiles();
175 SourceManager SM(Diagnostics, FileMgr);
176 Rewriter Rewrite(SM, LangOptions());
178 if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
179 llvm::errs() <<
"Failed applying all replacements.\n";
184 std::set<llvm::StringRef> Files;
185 for (
const auto &it : Tool.getReplacements())
186 Files.insert(it.first);
187 auto WriteToJson = [&](llvm::raw_ostream &OS) {
189 for (
auto I = Files.begin(), E = Files.end(); I != E; ++I) {
191 OS <<
" \"FilePath\": \"" << *I <<
"\",\n";
192 const auto *
Entry = FileMgr.getFile(*I);
193 auto ID = SM.translateFile(
Entry);
195 llvm::raw_string_ostream ContentStream(Content);
196 Rewrite.getEditBuffer(ID).write(ContentStream);
197 OS <<
" \"SourceText\": \"" 198 << llvm::yaml::escape(ContentStream.str()) <<
"\"\n";
200 if (I != std::prev(E))
205 WriteToJson(llvm::outs());
209 return Rewrite.overwriteChangedFiles();
Some operations such as code completion produce a set of candidates.
const std::vector< DeclarationPair > getDeclarationList() const
SmallVector< std::string, 4 > Names
int main(int argc, const char **argv)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//