You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			211 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			211 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | //===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
 | ||
|  | //
 | ||
|  | //                     The LLVM Compiler Infrastructure
 | ||
|  | //
 | ||
|  | // This file is distributed under the University of Illinois Open Source
 | ||
|  | // License. See LICENSE.TXT for details.
 | ||
|  | //
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | 
 | ||
|  | #include "ClangMove.h"
 | ||
|  | #include "clang/Frontend/TextDiagnosticPrinter.h"
 | ||
|  | #include "clang/Rewrite/Core/Rewriter.h"
 | ||
|  | #include "clang/Tooling/ArgumentsAdjusters.h"
 | ||
|  | #include "clang/Tooling/CommonOptionsParser.h"
 | ||
|  | #include "clang/Tooling/Refactoring.h"
 | ||
|  | #include "clang/Tooling/Tooling.h"
 | ||
|  | #include "llvm/ADT/StringRef.h"
 | ||
|  | #include "llvm/Support/CommandLine.h"
 | ||
|  | #include "llvm/Support/Path.h"
 | ||
|  | #include "llvm/Support/Process.h"
 | ||
|  | #include "llvm/Support/Signals.h"
 | ||
|  | #include "llvm/Support/YAMLTraits.h"
 | ||
|  | #include <set>
 | ||
|  | #include <string>
 | ||
|  | 
 | ||
|  | using namespace clang; | ||
|  | using namespace llvm; | ||
|  | 
 | ||
|  | namespace { | ||
|  | 
 | ||
|  | std::error_code CreateNewFile(const llvm::Twine &path) { | ||
|  |   int fd = 0; | ||
|  |   if (std::error_code ec = | ||
|  |           llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Text)) | ||
|  |     return ec; | ||
|  | 
 | ||
|  |   return llvm::sys::Process::SafelyCloseFileDescriptor(fd); | ||
|  | } | ||
|  | 
 | ||
|  | cl::OptionCategory ClangMoveCategory("clang-move options"); | ||
|  | 
 | ||
|  | cl::list<std::string> Names("names", cl::CommaSeparated, | ||
|  |                             cl::desc("The list of the names of classes being " | ||
|  |                                      "moved, e.g. \"Foo,a::Foo,b::Foo\"."), | ||
|  |                             cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<std::string> | ||
|  |     OldHeader("old_header", | ||
|  |               cl::desc("The relative/absolute file path of old header."), | ||
|  |               cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<std::string> | ||
|  |     OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."), | ||
|  |           cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<std::string> | ||
|  |     NewHeader("new_header", | ||
|  |               cl::desc("The relative/absolute file path of new header."), | ||
|  |               cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<std::string> | ||
|  |     NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."), | ||
|  |           cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<bool> | ||
|  |     OldDependOnNew("old_depend_on_new", | ||
|  |                    cl::desc("Whether old header will depend on new header. If " | ||
|  |                             "true, clang-move will " | ||
|  |                             "add #include of new header to old header."), | ||
|  |                    cl::init(false), cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<bool> | ||
|  |     NewDependOnOld("new_depend_on_old", | ||
|  |                    cl::desc("Whether new header will depend on old header. If " | ||
|  |                             "true, clang-move will " | ||
|  |                             "add #include of old header to new header."), | ||
|  |                    cl::init(false), cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<std::string> | ||
|  |     Style("style", | ||
|  |           cl::desc("The style name used for reformatting. Default is \"llvm\""), | ||
|  |           cl::init("llvm"), cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<bool> Dump("dump_result", | ||
|  |                    cl::desc("Dump results in JSON format to stdout."), | ||
|  |                    cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | cl::opt<bool> DumpDecls( | ||
|  |     "dump_decls", | ||
|  |     cl::desc("Dump all declarations in old header (JSON format) to stdout. If " | ||
|  |              "the option is specified, other command options will be ignored. " | ||
|  |              "An empty JSON will be returned if old header isn't specified."), | ||
|  |     cl::cat(ClangMoveCategory)); | ||
|  | 
 | ||
|  | } // namespace
 | ||
|  | 
 | ||
|  | int main(int argc, const char **argv) { | ||
|  |   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); | ||
|  |   tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory); | ||
|  | 
 | ||
|  |   if (OldDependOnNew && NewDependOnOld) { | ||
|  |     llvm::errs() << "Provide either --old_depend_on_new or " | ||
|  |                     "--new_depend_on_old. clang-move doesn't support these two " | ||
|  |                     "options at same time (It will introduce include cycle).\n"; | ||
|  |     return 1; | ||
|  |   } | ||
|  | 
 | ||
|  |   tooling::RefactoringTool Tool(OptionsParser.getCompilations(), | ||
|  |                                 OptionsParser.getSourcePathList()); | ||
|  |   // Add "-fparse-all-comments" compile option to make clang parse all comments.
 | ||
|  |   Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster( | ||
|  |       "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN)); | ||
|  |   move::MoveDefinitionSpec Spec; | ||
|  |   Spec.Names = {Names.begin(), Names.end()}; | ||
|  |   Spec.OldHeader = OldHeader; | ||
|  |   Spec.NewHeader = NewHeader; | ||
|  |   Spec.OldCC = OldCC; | ||
|  |   Spec.NewCC = NewCC; | ||
|  |   Spec.OldDependOnNew = OldDependOnNew; | ||
|  |   Spec.NewDependOnOld = NewDependOnOld; | ||
|  | 
 | ||
|  |   llvm::SmallString<128> InitialDirectory; | ||
|  |   if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory)) | ||
|  |     llvm::report_fatal_error("Cannot detect current path: " + | ||
|  |                              Twine(EC.message())); | ||
|  | 
 | ||
|  |   move::ClangMoveContext Context{Spec, Tool.getReplacements(), | ||
|  |                                  InitialDirectory.str(), Style, DumpDecls}; | ||
|  |   move::DeclarationReporter Reporter; | ||
|  |   move::ClangMoveActionFactory Factory(&Context, &Reporter); | ||
|  |    | ||
|  |   int CodeStatus = Tool.run(&Factory); | ||
|  |   if (CodeStatus) | ||
|  |     return CodeStatus; | ||
|  | 
 | ||
|  |   if (DumpDecls) { | ||
|  |     llvm::outs() << "[\n"; | ||
|  |     const auto &Declarations = Reporter.getDeclarationList(); | ||
|  |     for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) { | ||
|  |       llvm::outs() << "  {\n"; | ||
|  |       llvm::outs() << "    \"DeclarationName\": \"" << I->first << "\",\n"; | ||
|  |       llvm::outs() << "    \"DeclarationType\": \"" << I->second << "\"\n"; | ||
|  |       llvm::outs() << "  }"; | ||
|  |       // Don't print trailing "," at the end of last element.
 | ||
|  |       if (I != std::prev(E)) | ||
|  |         llvm::outs() << ",\n"; | ||
|  |     } | ||
|  |     llvm::outs() << "\n]\n"; | ||
|  |     return 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (!NewCC.empty()) { | ||
|  |     std::error_code EC = CreateNewFile(NewCC); | ||
|  |     if (EC) { | ||
|  |       llvm::errs() << "Failed to create " << NewCC << ": " << EC.message() | ||
|  |                    << "\n"; | ||
|  |       return EC.value(); | ||
|  |     } | ||
|  |   } | ||
|  |   if (!NewHeader.empty()) { | ||
|  |     std::error_code EC = CreateNewFile(NewHeader); | ||
|  |     if (EC) { | ||
|  |       llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message() | ||
|  |                    << "\n"; | ||
|  |       return EC.value(); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions()); | ||
|  |   clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); | ||
|  |   DiagnosticsEngine Diagnostics( | ||
|  |       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, | ||
|  |       &DiagnosticPrinter, false); | ||
|  |   auto &FileMgr = Tool.getFiles(); | ||
|  |   SourceManager SM(Diagnostics, FileMgr); | ||
|  |   Rewriter Rewrite(SM, LangOptions()); | ||
|  | 
 | ||
|  |   if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) { | ||
|  |     llvm::errs() << "Failed applying all replacements.\n"; | ||
|  |     return 1; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (Dump) { | ||
|  |     std::set<llvm::StringRef> Files; | ||
|  |     for (const auto &it : Tool.getReplacements()) | ||
|  |       Files.insert(it.first); | ||
|  |     auto WriteToJson = [&](llvm::raw_ostream &OS) { | ||
|  |       OS << "[\n"; | ||
|  |       for (auto I = Files.begin(), E = Files.end(); I != E; ++I) { | ||
|  |         OS << "  {\n"; | ||
|  |         OS << "    \"FilePath\": \"" << *I << "\",\n"; | ||
|  |         const auto *Entry = FileMgr.getFile(*I); | ||
|  |         auto ID = SM.translateFile(Entry); | ||
|  |         std::string Content; | ||
|  |         llvm::raw_string_ostream ContentStream(Content); | ||
|  |         Rewrite.getEditBuffer(ID).write(ContentStream); | ||
|  |         OS << "    \"SourceText\": \"" | ||
|  |            << llvm::yaml::escape(ContentStream.str()) << "\"\n"; | ||
|  |         OS << "  }"; | ||
|  |         if (I != std::prev(E)) | ||
|  |           OS << ",\n"; | ||
|  |       } | ||
|  |       OS << "\n]\n"; | ||
|  |     }; | ||
|  |     WriteToJson(llvm::outs()); | ||
|  |     return 0; | ||
|  |   } | ||
|  | 
 | ||
|  |   return Rewrite.overwriteChangedFiles(); | ||
|  | } |