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