1 | //===- ClangSrcLocDump.cpp ------------------------------------*- C++ -*---===//
|
2 | //
|
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
4 | // See https://llvm.org/LICENSE.txt for license information.
|
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
6 | //
|
7 | //===----------------------------------------------------------------------===//
|
8 |
|
9 | #include "clang/Basic/Diagnostic.h"
|
10 | #include "clang/Driver/Compilation.h"
|
11 | #include "clang/Driver/Driver.h"
|
12 | #include "clang/Driver/Job.h"
|
13 | #include "clang/Driver/Options.h"
|
14 | #include "clang/Driver/Tool.h"
|
15 | #include "clang/Frontend/CompilerInstance.h"
|
16 | #include "clang/Frontend/TextDiagnosticPrinter.h"
|
17 | #include "clang/Lex/PreprocessorOptions.h"
|
18 | #include "clang/Tooling/Tooling.h"
|
19 | #include "llvm/Option/ArgList.h"
|
20 | #include "llvm/Support/CommandLine.h"
|
21 | #include "llvm/Support/JSON.h"
|
22 | #include "llvm/TargetParser/Host.h"
|
23 |
|
24 | #include "ASTSrcLocProcessor.h"
|
25 |
|
26 | using namespace clang::tooling;
|
27 | using namespace clang;
|
28 | using namespace llvm;
|
29 |
|
30 | static cl::list<std::string> IncludeDirectories(
|
31 | "I" , cl::desc("Include directories to use while compiling" ),
|
32 | cl::value_desc("directory" ), cl::Required, cl::OneOrMore, cl::Prefix);
|
33 |
|
34 | static cl::opt<bool>
|
35 | SkipProcessing("skip-processing" ,
|
36 | cl::desc("Avoid processing the AST header file" ),
|
37 | cl::Required, cl::value_desc("bool" ));
|
38 |
|
39 | static cl::opt<std::string> JsonOutputPath("json-output-path" ,
|
40 | cl::desc("json output path" ),
|
41 | cl::Required,
|
42 | cl::value_desc("path" ));
|
43 |
|
44 | class ASTSrcLocGenerationAction : public clang::ASTFrontendAction {
|
45 | public:
|
46 | ASTSrcLocGenerationAction() : Processor(JsonOutputPath) {}
|
47 |
|
48 | void ExecuteAction() override {
|
49 | clang::ASTFrontendAction::ExecuteAction();
|
50 | if (getCompilerInstance().getDiagnostics().getNumErrors() > 0)
|
51 | Processor.generateEmpty();
|
52 | else
|
53 | Processor.generate();
|
54 | }
|
55 |
|
56 | std::unique_ptr<clang::ASTConsumer>
|
57 | CreateASTConsumer(clang::CompilerInstance &Compiler,
|
58 | llvm::StringRef File) override {
|
59 | return Processor.createASTConsumer(Compiler, File);
|
60 | }
|
61 |
|
62 | private:
|
63 | ASTSrcLocProcessor Processor;
|
64 | };
|
65 |
|
66 | static const char Filename[] = "ASTTU.cpp" ;
|
67 |
|
68 | int main(int argc, const char **argv) {
|
69 |
|
70 | cl::ParseCommandLineOptions(argc, argv);
|
71 |
|
72 | if (SkipProcessing) {
|
73 | std::error_code EC;
|
74 | llvm::raw_fd_ostream JsonOut(JsonOutputPath, EC, llvm::sys::fs::OF_Text);
|
75 | if (EC)
|
76 | return 1;
|
77 | JsonOut << formatv(Fmt: "{0:2}" , Vals: llvm::json::Value(llvm::json::Object()));
|
78 | return 0;
|
79 | }
|
80 |
|
81 | std::vector<std::string> Args;
|
82 | Args.push_back(x: "-cc1" );
|
83 |
|
84 | llvm::transform(Range&: IncludeDirectories, d_first: std::back_inserter(x&: Args),
|
85 | F: [](const std::string &IncDir) { return "-I" + IncDir; });
|
86 |
|
87 | Args.push_back(x: "-fsyntax-only" );
|
88 | Args.push_back(x: Filename);
|
89 |
|
90 | std::vector<const char *> Argv(Args.size(), nullptr);
|
91 | llvm::transform(Range&: Args, d_first: Argv.begin(),
|
92 | F: [](const std::string &Arg) { return Arg.c_str(); });
|
93 |
|
94 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
|
95 | CreateAndPopulateDiagOpts(Argv);
|
96 |
|
97 | // Don't output diagnostics, because common scenarios such as
|
98 | // cross-compiling fail with diagnostics. This is not fatal, but
|
99 | // just causes attempts to use the introspection API to return no data.
|
100 | TextDiagnosticPrinter DiagnosticPrinter(llvm::nulls(), &*DiagOpts);
|
101 | DiagnosticsEngine Diagnostics(
|
102 | IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
|
103 | &DiagnosticPrinter, false);
|
104 |
|
105 | auto *OFS = new llvm::vfs::OverlayFileSystem(vfs::getRealFileSystem());
|
106 |
|
107 | auto *MemFS = new llvm::vfs::InMemoryFileSystem();
|
108 | OFS->pushOverlay(FS: MemFS);
|
109 | MemFS->addFile(Path: Filename, ModificationTime: 0,
|
110 | Buffer: MemoryBuffer::getMemBuffer(InputData: "#include \"clang/AST/AST.h\"\n" ));
|
111 |
|
112 | auto Files = llvm::makeIntrusiveRefCnt<FileManager>(A: FileSystemOptions(), A&: OFS);
|
113 |
|
114 | auto Driver = std::make_unique<clang::driver::Driver>(
|
115 | args: "clang" , args: llvm::sys::getDefaultTargetTriple(), args&: Diagnostics,
|
116 | args: "ast-api-dump-tool" , args&: OFS);
|
117 |
|
118 | std::unique_ptr<clang::driver::Compilation> Comp(
|
119 | Driver->BuildCompilation(Args: llvm::ArrayRef(Argv)));
|
120 | if (!Comp)
|
121 | return 1;
|
122 |
|
123 | const auto &Jobs = Comp->getJobs();
|
124 | if (Jobs.size() != 1 || !isa<clang::driver::Command>(Val: *Jobs.begin())) {
|
125 | SmallString<256> error_msg;
|
126 | llvm::raw_svector_ostream error_stream(error_msg);
|
127 | Jobs.Print(OS&: error_stream, Terminator: "; " , Quote: true);
|
128 | return 1;
|
129 | }
|
130 |
|
131 | const auto &Cmd = cast<clang::driver::Command>(Val&: *Jobs.begin());
|
132 | const llvm::opt::ArgStringList &CC1Args = Cmd.getArguments();
|
133 |
|
134 | auto Invocation = std::make_unique<CompilerInvocation>();
|
135 | CompilerInvocation::CreateFromArgs(Res&: *Invocation, CommandLineArgs: CC1Args, Diags&: Diagnostics);
|
136 |
|
137 | CompilerInstance Compiler(std::make_shared<clang::PCHContainerOperations>());
|
138 | Compiler.setInvocation(std::move(Invocation));
|
139 |
|
140 | Compiler.createDiagnostics(Client: &DiagnosticPrinter, ShouldOwnClient: false);
|
141 | if (!Compiler.hasDiagnostics())
|
142 | return 1;
|
143 |
|
144 | // Suppress "2 errors generated" or similar messages
|
145 | Compiler.getDiagnosticOpts().ShowCarets = false;
|
146 | Compiler.createSourceManager(FileMgr&: *Files);
|
147 | Compiler.setFileManager(Files.get());
|
148 |
|
149 | ASTSrcLocGenerationAction ScopedToolAction;
|
150 | Compiler.ExecuteAction(Act&: ScopedToolAction);
|
151 |
|
152 | Files->clearStatCache();
|
153 |
|
154 | return 0;
|
155 | }
|
156 | |