annotate clang/lib/Tooling/Tooling.cpp @ 266:00f31e85ec16 default tip

Added tag current for changeset 31d058e83c98
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 14 Oct 2023 10:13:55 +0900
parents 1f2b6ac9f198
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- Tooling.cpp - Running clang standalone tools -----------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file implements functions to run clang tools standalone instead
anatofuz
parents:
diff changeset
10 // of running them as a plugin.
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
13
anatofuz
parents:
diff changeset
14 #include "clang/Tooling/Tooling.h"
anatofuz
parents:
diff changeset
15 #include "clang/Basic/Diagnostic.h"
anatofuz
parents:
diff changeset
16 #include "clang/Basic/DiagnosticIDs.h"
anatofuz
parents:
diff changeset
17 #include "clang/Basic/DiagnosticOptions.h"
anatofuz
parents:
diff changeset
18 #include "clang/Basic/FileManager.h"
anatofuz
parents:
diff changeset
19 #include "clang/Basic/FileSystemOptions.h"
anatofuz
parents:
diff changeset
20 #include "clang/Basic/LLVM.h"
anatofuz
parents:
diff changeset
21 #include "clang/Driver/Compilation.h"
anatofuz
parents:
diff changeset
22 #include "clang/Driver/Driver.h"
anatofuz
parents:
diff changeset
23 #include "clang/Driver/Job.h"
anatofuz
parents:
diff changeset
24 #include "clang/Driver/Options.h"
anatofuz
parents:
diff changeset
25 #include "clang/Driver/Tool.h"
anatofuz
parents:
diff changeset
26 #include "clang/Driver/ToolChain.h"
anatofuz
parents:
diff changeset
27 #include "clang/Frontend/ASTUnit.h"
anatofuz
parents:
diff changeset
28 #include "clang/Frontend/CompilerInstance.h"
anatofuz
parents:
diff changeset
29 #include "clang/Frontend/CompilerInvocation.h"
anatofuz
parents:
diff changeset
30 #include "clang/Frontend/FrontendDiagnostic.h"
anatofuz
parents:
diff changeset
31 #include "clang/Frontend/FrontendOptions.h"
anatofuz
parents:
diff changeset
32 #include "clang/Frontend/TextDiagnosticPrinter.h"
anatofuz
parents:
diff changeset
33 #include "clang/Lex/HeaderSearchOptions.h"
anatofuz
parents:
diff changeset
34 #include "clang/Lex/PreprocessorOptions.h"
anatofuz
parents:
diff changeset
35 #include "clang/Tooling/ArgumentsAdjusters.h"
anatofuz
parents:
diff changeset
36 #include "clang/Tooling/CompilationDatabase.h"
anatofuz
parents:
diff changeset
37 #include "llvm/ADT/ArrayRef.h"
anatofuz
parents:
diff changeset
38 #include "llvm/ADT/IntrusiveRefCntPtr.h"
anatofuz
parents:
diff changeset
39 #include "llvm/ADT/SmallString.h"
anatofuz
parents:
diff changeset
40 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
41 #include "llvm/ADT/Twine.h"
anatofuz
parents:
diff changeset
42 #include "llvm/Option/ArgList.h"
anatofuz
parents:
diff changeset
43 #include "llvm/Option/OptTable.h"
anatofuz
parents:
diff changeset
44 #include "llvm/Option/Option.h"
anatofuz
parents:
diff changeset
45 #include "llvm/Support/Casting.h"
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
46 #include "llvm/Support/CommandLine.h"
150
anatofuz
parents:
diff changeset
47 #include "llvm/Support/Debug.h"
anatofuz
parents:
diff changeset
48 #include "llvm/Support/ErrorHandling.h"
anatofuz
parents:
diff changeset
49 #include "llvm/Support/FileSystem.h"
anatofuz
parents:
diff changeset
50 #include "llvm/Support/MemoryBuffer.h"
anatofuz
parents:
diff changeset
51 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
52 #include "llvm/Support/VirtualFileSystem.h"
anatofuz
parents:
diff changeset
53 #include "llvm/Support/raw_ostream.h"
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
54 #include "llvm/TargetParser/Host.h"
150
anatofuz
parents:
diff changeset
55 #include <cassert>
anatofuz
parents:
diff changeset
56 #include <cstring>
anatofuz
parents:
diff changeset
57 #include <memory>
anatofuz
parents:
diff changeset
58 #include <string>
anatofuz
parents:
diff changeset
59 #include <system_error>
anatofuz
parents:
diff changeset
60 #include <utility>
anatofuz
parents:
diff changeset
61 #include <vector>
anatofuz
parents:
diff changeset
62
anatofuz
parents:
diff changeset
63 #define DEBUG_TYPE "clang-tooling"
anatofuz
parents:
diff changeset
64
anatofuz
parents:
diff changeset
65 using namespace clang;
anatofuz
parents:
diff changeset
66 using namespace tooling;
anatofuz
parents:
diff changeset
67
anatofuz
parents:
diff changeset
68 ToolAction::~ToolAction() = default;
anatofuz
parents:
diff changeset
69
anatofuz
parents:
diff changeset
70 FrontendActionFactory::~FrontendActionFactory() = default;
anatofuz
parents:
diff changeset
71
anatofuz
parents:
diff changeset
72 // FIXME: This file contains structural duplication with other parts of the
anatofuz
parents:
diff changeset
73 // code that sets up a compiler to run tools on it, and we should refactor
anatofuz
parents:
diff changeset
74 // it to be based on the same framework.
anatofuz
parents:
diff changeset
75
anatofuz
parents:
diff changeset
76 /// Builds a clang driver initialized for running clang tools.
anatofuz
parents:
diff changeset
77 static driver::Driver *
anatofuz
parents:
diff changeset
78 newDriver(DiagnosticsEngine *Diagnostics, const char *BinaryName,
anatofuz
parents:
diff changeset
79 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
anatofuz
parents:
diff changeset
80 driver::Driver *CompilerDriver =
anatofuz
parents:
diff changeset
81 new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(),
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
82 *Diagnostics, "clang LLVM compiler", std::move(VFS));
150
anatofuz
parents:
diff changeset
83 CompilerDriver->setTitle("clang_based_tool");
anatofuz
parents:
diff changeset
84 return CompilerDriver;
anatofuz
parents:
diff changeset
85 }
anatofuz
parents:
diff changeset
86
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
87 /// Decide whether extra compiler frontend commands can be ignored.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
88 static bool ignoreExtraCC1Commands(const driver::Compilation *Compilation) {
150
anatofuz
parents:
diff changeset
89 const driver::JobList &Jobs = Compilation->getJobs();
anatofuz
parents:
diff changeset
90 const driver::ActionList &Actions = Compilation->getActions();
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
91
150
anatofuz
parents:
diff changeset
92 bool OffloadCompilation = false;
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
93
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
94 // Jobs and Actions look very different depending on whether the Clang tool
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
95 // injected -fsyntax-only or not. Try to handle both cases here.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
96
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
97 for (const auto &Job : Jobs)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
98 if (StringRef(Job.getExecutable()) == "clang-offload-bundler")
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
99 OffloadCompilation = true;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
100
150
anatofuz
parents:
diff changeset
101 if (Jobs.size() > 1) {
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
102 for (auto *A : Actions){
150
anatofuz
parents:
diff changeset
103 // On MacOSX real actions may end up being wrapped in BindArchAction
anatofuz
parents:
diff changeset
104 if (isa<driver::BindArchAction>(A))
anatofuz
parents:
diff changeset
105 A = *A->input_begin();
anatofuz
parents:
diff changeset
106 if (isa<driver::OffloadAction>(A)) {
anatofuz
parents:
diff changeset
107 // Offload compilation has 2 top-level actions, one (at the front) is
anatofuz
parents:
diff changeset
108 // the original host compilation and the other is offload action
anatofuz
parents:
diff changeset
109 // composed of at least one device compilation. For such case, general
anatofuz
parents:
diff changeset
110 // tooling will consider host-compilation only. For tooling on device
anatofuz
parents:
diff changeset
111 // compilation, device compilation only option, such as
anatofuz
parents:
diff changeset
112 // `--cuda-device-only`, needs specifying.
anatofuz
parents:
diff changeset
113 assert(Actions.size() > 1);
anatofuz
parents:
diff changeset
114 assert(
anatofuz
parents:
diff changeset
115 isa<driver::CompileJobAction>(Actions.front()) ||
anatofuz
parents:
diff changeset
116 // On MacOSX real actions may end up being wrapped in
anatofuz
parents:
diff changeset
117 // BindArchAction.
anatofuz
parents:
diff changeset
118 (isa<driver::BindArchAction>(Actions.front()) &&
anatofuz
parents:
diff changeset
119 isa<driver::CompileJobAction>(*Actions.front()->input_begin())));
anatofuz
parents:
diff changeset
120 OffloadCompilation = true;
anatofuz
parents:
diff changeset
121 break;
anatofuz
parents:
diff changeset
122 }
anatofuz
parents:
diff changeset
123 }
anatofuz
parents:
diff changeset
124 }
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
125
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
126 return OffloadCompilation;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
127 }
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
128
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
129 namespace clang {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
130 namespace tooling {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
131
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
132 const llvm::opt::ArgStringList *
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
133 getCC1Arguments(DiagnosticsEngine *Diagnostics,
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
134 driver::Compilation *Compilation) {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
135 const driver::JobList &Jobs = Compilation->getJobs();
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
136
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
137 auto IsCC1Command = [](const driver::Command &Cmd) {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
138 return StringRef(Cmd.getCreator().getName()) == "clang";
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
139 };
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
140
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
141 auto IsSrcFile = [](const driver::InputInfo &II) {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
142 return isSrcFile(II.getType());
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
143 };
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
144
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
145 llvm::SmallVector<const driver::Command *, 1> CC1Jobs;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
146 for (const driver::Command &Job : Jobs)
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
147 if (IsCC1Command(Job) && llvm::all_of(Job.getInputInfos(), IsSrcFile))
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
148 CC1Jobs.push_back(&Job);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
149
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
150 // If there are no jobs for source files, try checking again for a single job
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
151 // with any file type. This accepts a preprocessed file as input.
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
152 if (CC1Jobs.empty())
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
153 for (const driver::Command &Job : Jobs)
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
154 if (IsCC1Command(Job))
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
155 CC1Jobs.push_back(&Job);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
156
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
157 if (CC1Jobs.empty() ||
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
158 (CC1Jobs.size() > 1 && !ignoreExtraCC1Commands(Compilation))) {
150
anatofuz
parents:
diff changeset
159 SmallString<256> error_msg;
anatofuz
parents:
diff changeset
160 llvm::raw_svector_ostream error_stream(error_msg);
anatofuz
parents:
diff changeset
161 Jobs.Print(error_stream, "; ", true);
anatofuz
parents:
diff changeset
162 Diagnostics->Report(diag::err_fe_expected_compiler_job)
anatofuz
parents:
diff changeset
163 << error_stream.str();
anatofuz
parents:
diff changeset
164 return nullptr;
anatofuz
parents:
diff changeset
165 }
anatofuz
parents:
diff changeset
166
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
167 return &CC1Jobs[0]->getArguments();
150
anatofuz
parents:
diff changeset
168 }
anatofuz
parents:
diff changeset
169
anatofuz
parents:
diff changeset
170 /// Returns a clang build invocation initialized from the CC1 flags.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
171 CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics,
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
172 ArrayRef<const char *> CC1Args,
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
173 const char *const BinaryName) {
150
anatofuz
parents:
diff changeset
174 assert(!CC1Args.empty() && "Must at least contain the program name!");
anatofuz
parents:
diff changeset
175 CompilerInvocation *Invocation = new CompilerInvocation;
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
176 CompilerInvocation::CreateFromArgs(*Invocation, CC1Args, *Diagnostics,
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
177 BinaryName);
150
anatofuz
parents:
diff changeset
178 Invocation->getFrontendOpts().DisableFree = false;
anatofuz
parents:
diff changeset
179 Invocation->getCodeGenOpts().DisableFree = false;
anatofuz
parents:
diff changeset
180 return Invocation;
anatofuz
parents:
diff changeset
181 }
anatofuz
parents:
diff changeset
182
anatofuz
parents:
diff changeset
183 bool runToolOnCode(std::unique_ptr<FrontendAction> ToolAction,
anatofuz
parents:
diff changeset
184 const Twine &Code, const Twine &FileName,
anatofuz
parents:
diff changeset
185 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
anatofuz
parents:
diff changeset
186 return runToolOnCodeWithArgs(std::move(ToolAction), Code,
anatofuz
parents:
diff changeset
187 std::vector<std::string>(), FileName,
anatofuz
parents:
diff changeset
188 "clang-tool", std::move(PCHContainerOps));
anatofuz
parents:
diff changeset
189 }
anatofuz
parents:
diff changeset
190
anatofuz
parents:
diff changeset
191 } // namespace tooling
anatofuz
parents:
diff changeset
192 } // namespace clang
anatofuz
parents:
diff changeset
193
anatofuz
parents:
diff changeset
194 static std::vector<std::string>
anatofuz
parents:
diff changeset
195 getSyntaxOnlyToolArgs(const Twine &ToolName,
anatofuz
parents:
diff changeset
196 const std::vector<std::string> &ExtraArgs,
anatofuz
parents:
diff changeset
197 StringRef FileName) {
anatofuz
parents:
diff changeset
198 std::vector<std::string> Args;
anatofuz
parents:
diff changeset
199 Args.push_back(ToolName.str());
anatofuz
parents:
diff changeset
200 Args.push_back("-fsyntax-only");
anatofuz
parents:
diff changeset
201 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
anatofuz
parents:
diff changeset
202 Args.push_back(FileName.str());
anatofuz
parents:
diff changeset
203 return Args;
anatofuz
parents:
diff changeset
204 }
anatofuz
parents:
diff changeset
205
anatofuz
parents:
diff changeset
206 namespace clang {
anatofuz
parents:
diff changeset
207 namespace tooling {
anatofuz
parents:
diff changeset
208
anatofuz
parents:
diff changeset
209 bool runToolOnCodeWithArgs(
anatofuz
parents:
diff changeset
210 std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
anatofuz
parents:
diff changeset
211 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
anatofuz
parents:
diff changeset
212 const std::vector<std::string> &Args, const Twine &FileName,
anatofuz
parents:
diff changeset
213 const Twine &ToolName,
anatofuz
parents:
diff changeset
214 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
anatofuz
parents:
diff changeset
215 SmallString<16> FileNameStorage;
anatofuz
parents:
diff changeset
216 StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
anatofuz
parents:
diff changeset
217
anatofuz
parents:
diff changeset
218 llvm::IntrusiveRefCntPtr<FileManager> Files(
anatofuz
parents:
diff changeset
219 new FileManager(FileSystemOptions(), VFS));
anatofuz
parents:
diff changeset
220 ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
anatofuz
parents:
diff changeset
221 ToolInvocation Invocation(
anatofuz
parents:
diff changeset
222 getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
anatofuz
parents:
diff changeset
223 std::move(ToolAction), Files.get(), std::move(PCHContainerOps));
anatofuz
parents:
diff changeset
224 return Invocation.run();
anatofuz
parents:
diff changeset
225 }
anatofuz
parents:
diff changeset
226
anatofuz
parents:
diff changeset
227 bool runToolOnCodeWithArgs(
anatofuz
parents:
diff changeset
228 std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
anatofuz
parents:
diff changeset
229 const std::vector<std::string> &Args, const Twine &FileName,
anatofuz
parents:
diff changeset
230 const Twine &ToolName,
anatofuz
parents:
diff changeset
231 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
anatofuz
parents:
diff changeset
232 const FileContentMappings &VirtualMappedFiles) {
anatofuz
parents:
diff changeset
233 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
anatofuz
parents:
diff changeset
234 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
anatofuz
parents:
diff changeset
235 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
anatofuz
parents:
diff changeset
236 new llvm::vfs::InMemoryFileSystem);
anatofuz
parents:
diff changeset
237 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 SmallString<1024> CodeStorage;
anatofuz
parents:
diff changeset
240 InMemoryFileSystem->addFile(FileName, 0,
anatofuz
parents:
diff changeset
241 llvm::MemoryBuffer::getMemBuffer(
anatofuz
parents:
diff changeset
242 Code.toNullTerminatedStringRef(CodeStorage)));
anatofuz
parents:
diff changeset
243
anatofuz
parents:
diff changeset
244 for (auto &FilenameWithContent : VirtualMappedFiles) {
anatofuz
parents:
diff changeset
245 InMemoryFileSystem->addFile(
anatofuz
parents:
diff changeset
246 FilenameWithContent.first, 0,
anatofuz
parents:
diff changeset
247 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
anatofuz
parents:
diff changeset
248 }
anatofuz
parents:
diff changeset
249
anatofuz
parents:
diff changeset
250 return runToolOnCodeWithArgs(std::move(ToolAction), Code, OverlayFileSystem,
anatofuz
parents:
diff changeset
251 Args, FileName, ToolName);
anatofuz
parents:
diff changeset
252 }
anatofuz
parents:
diff changeset
253
anatofuz
parents:
diff changeset
254 llvm::Expected<std::string> getAbsolutePath(llvm::vfs::FileSystem &FS,
anatofuz
parents:
diff changeset
255 StringRef File) {
anatofuz
parents:
diff changeset
256 StringRef RelativePath(File);
anatofuz
parents:
diff changeset
257 // FIXME: Should '.\\' be accepted on Win32?
anatofuz
parents:
diff changeset
258 if (RelativePath.startswith("./")) {
anatofuz
parents:
diff changeset
259 RelativePath = RelativePath.substr(strlen("./"));
anatofuz
parents:
diff changeset
260 }
anatofuz
parents:
diff changeset
261
anatofuz
parents:
diff changeset
262 SmallString<1024> AbsolutePath = RelativePath;
anatofuz
parents:
diff changeset
263 if (auto EC = FS.makeAbsolute(AbsolutePath))
anatofuz
parents:
diff changeset
264 return llvm::errorCodeToError(EC);
anatofuz
parents:
diff changeset
265 llvm::sys::path::native(AbsolutePath);
anatofuz
parents:
diff changeset
266 return std::string(AbsolutePath.str());
anatofuz
parents:
diff changeset
267 }
anatofuz
parents:
diff changeset
268
anatofuz
parents:
diff changeset
269 std::string getAbsolutePath(StringRef File) {
anatofuz
parents:
diff changeset
270 return llvm::cantFail(getAbsolutePath(*llvm::vfs::getRealFileSystem(), File));
anatofuz
parents:
diff changeset
271 }
anatofuz
parents:
diff changeset
272
anatofuz
parents:
diff changeset
273 void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
anatofuz
parents:
diff changeset
274 StringRef InvokedAs) {
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
275 if (CommandLine.empty() || InvokedAs.empty())
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
276 return;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
277 const auto &Table = driver::getDriverOptTable();
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
278 // --target=X
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
279 StringRef TargetOPT =
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
280 Table.getOption(driver::options::OPT_target).getPrefixedName();
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
281 // -target X
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
282 StringRef TargetOPTLegacy =
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
283 Table.getOption(driver::options::OPT_target_legacy_spelling)
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
284 .getPrefixedName();
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
285 // --driver-mode=X
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
286 StringRef DriverModeOPT =
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
287 Table.getOption(driver::options::OPT_driver_mode).getPrefixedName();
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
288 auto TargetMode =
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
289 driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
290 // No need to search for target args if we don't have a target/mode to insert.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
291 bool ShouldAddTarget = TargetMode.TargetIsValid;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
292 bool ShouldAddMode = TargetMode.DriverMode != nullptr;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
293 // Skip CommandLine[0].
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
294 for (auto Token = ++CommandLine.begin(); Token != CommandLine.end();
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
295 ++Token) {
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
296 StringRef TokenRef(*Token);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
297 ShouldAddTarget = ShouldAddTarget && !TokenRef.startswith(TargetOPT) &&
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
298 !TokenRef.equals(TargetOPTLegacy);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
299 ShouldAddMode = ShouldAddMode && !TokenRef.startswith(DriverModeOPT);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
300 }
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
301 if (ShouldAddMode) {
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
302 CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
303 }
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
304 if (ShouldAddTarget) {
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
305 CommandLine.insert(++CommandLine.begin(),
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
306 (TargetOPT + TargetMode.TargetPrefix).str());
150
anatofuz
parents:
diff changeset
307 }
anatofuz
parents:
diff changeset
308 }
anatofuz
parents:
diff changeset
309
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
310 void addExpandedResponseFiles(std::vector<std::string> &CommandLine,
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
311 llvm::StringRef WorkingDir,
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
312 llvm::cl::TokenizerCallback Tokenizer,
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
313 llvm::vfs::FileSystem &FS) {
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
314 bool SeenRSPFile = false;
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
315 llvm::SmallVector<const char *, 20> Argv;
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
316 Argv.reserve(CommandLine.size());
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
317 for (auto &Arg : CommandLine) {
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
318 Argv.push_back(Arg.c_str());
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
319 if (!Arg.empty())
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
320 SeenRSPFile |= Arg.front() == '@';
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
321 }
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
322 if (!SeenRSPFile)
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
323 return;
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
324 llvm::BumpPtrAllocator Alloc;
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
325 llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
326 llvm::Error Err =
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
327 ECtx.setVFS(&FS).setCurrentDir(WorkingDir).expandResponseFiles(Argv);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
328 if (Err)
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
329 llvm::errs() << Err;
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
330 // Don't assign directly, Argv aliases CommandLine.
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
331 std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
332 CommandLine = std::move(ExpandedArgv);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
333 }
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
334
150
anatofuz
parents:
diff changeset
335 } // namespace tooling
anatofuz
parents:
diff changeset
336 } // namespace clang
anatofuz
parents:
diff changeset
337
anatofuz
parents:
diff changeset
338 namespace {
anatofuz
parents:
diff changeset
339
anatofuz
parents:
diff changeset
340 class SingleFrontendActionFactory : public FrontendActionFactory {
anatofuz
parents:
diff changeset
341 std::unique_ptr<FrontendAction> Action;
anatofuz
parents:
diff changeset
342
anatofuz
parents:
diff changeset
343 public:
anatofuz
parents:
diff changeset
344 SingleFrontendActionFactory(std::unique_ptr<FrontendAction> Action)
anatofuz
parents:
diff changeset
345 : Action(std::move(Action)) {}
anatofuz
parents:
diff changeset
346
anatofuz
parents:
diff changeset
347 std::unique_ptr<FrontendAction> create() override {
anatofuz
parents:
diff changeset
348 return std::move(Action);
anatofuz
parents:
diff changeset
349 }
anatofuz
parents:
diff changeset
350 };
anatofuz
parents:
diff changeset
351
anatofuz
parents:
diff changeset
352 } // namespace
anatofuz
parents:
diff changeset
353
anatofuz
parents:
diff changeset
354 ToolInvocation::ToolInvocation(
anatofuz
parents:
diff changeset
355 std::vector<std::string> CommandLine, ToolAction *Action,
anatofuz
parents:
diff changeset
356 FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
anatofuz
parents:
diff changeset
357 : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(false),
anatofuz
parents:
diff changeset
358 Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
anatofuz
parents:
diff changeset
359
anatofuz
parents:
diff changeset
360 ToolInvocation::ToolInvocation(
anatofuz
parents:
diff changeset
361 std::vector<std::string> CommandLine,
anatofuz
parents:
diff changeset
362 std::unique_ptr<FrontendAction> FAction, FileManager *Files,
anatofuz
parents:
diff changeset
363 std::shared_ptr<PCHContainerOperations> PCHContainerOps)
anatofuz
parents:
diff changeset
364 : CommandLine(std::move(CommandLine)),
anatofuz
parents:
diff changeset
365 Action(new SingleFrontendActionFactory(std::move(FAction))),
anatofuz
parents:
diff changeset
366 OwnsAction(true), Files(Files),
anatofuz
parents:
diff changeset
367 PCHContainerOps(std::move(PCHContainerOps)) {}
anatofuz
parents:
diff changeset
368
anatofuz
parents:
diff changeset
369 ToolInvocation::~ToolInvocation() {
anatofuz
parents:
diff changeset
370 if (OwnsAction)
anatofuz
parents:
diff changeset
371 delete Action;
anatofuz
parents:
diff changeset
372 }
anatofuz
parents:
diff changeset
373
anatofuz
parents:
diff changeset
374 bool ToolInvocation::run() {
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
375 llvm::opt::ArgStringList Argv;
150
anatofuz
parents:
diff changeset
376 for (const std::string &Str : CommandLine)
anatofuz
parents:
diff changeset
377 Argv.push_back(Str.c_str());
anatofuz
parents:
diff changeset
378 const char *const BinaryName = Argv[0];
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
379
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
380 // Parse diagnostic options from the driver command-line only if none were
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
381 // explicitly set.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
382 IntrusiveRefCntPtr<DiagnosticOptions> ParsedDiagOpts;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
383 DiagnosticOptions *DiagOpts = this->DiagOpts;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
384 if (!DiagOpts) {
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
385 ParsedDiagOpts = CreateAndPopulateDiagOpts(Argv);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
386 DiagOpts = &*ParsedDiagOpts;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
387 }
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
388
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
389 TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
390 IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics =
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
391 CompilerInstance::createDiagnostics(
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
392 &*DiagOpts, DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
393 // Although `Diagnostics` are used only for command-line parsing, the custom
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
394 // `DiagConsumer` might expect a `SourceManager` to be present.
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
395 SourceManager SrcMgr(*Diagnostics, *Files);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
396 Diagnostics->setSourceManager(&SrcMgr);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
397
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
398 // We already have a cc1, just create an invocation.
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
399 if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") {
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
400 ArrayRef<const char *> CC1Args = ArrayRef(Argv).drop_front();
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
401 std::unique_ptr<CompilerInvocation> Invocation(
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
402 newInvocation(&*Diagnostics, CC1Args, BinaryName));
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
403 if (Diagnostics->hasErrorOccurred())
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
404 return false;
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
405 return Action->runInvocation(std::move(Invocation), Files,
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
406 std::move(PCHContainerOps), DiagConsumer);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
407 }
150
anatofuz
parents:
diff changeset
408
anatofuz
parents:
diff changeset
409 const std::unique_ptr<driver::Driver> Driver(
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
410 newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem()));
150
anatofuz
parents:
diff changeset
411 // The "input file not found" diagnostics from the driver are useful.
anatofuz
parents:
diff changeset
412 // The driver is only aware of the VFS working directory, but some clients
anatofuz
parents:
diff changeset
413 // change this at the FileManager level instead.
anatofuz
parents:
diff changeset
414 // In this case the checks have false positives, so skip them.
anatofuz
parents:
diff changeset
415 if (!Files->getFileSystemOpts().WorkingDir.empty())
anatofuz
parents:
diff changeset
416 Driver->setCheckInputsExist(false);
anatofuz
parents:
diff changeset
417 const std::unique_ptr<driver::Compilation> Compilation(
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
418 Driver->BuildCompilation(llvm::ArrayRef(Argv)));
150
anatofuz
parents:
diff changeset
419 if (!Compilation)
anatofuz
parents:
diff changeset
420 return false;
anatofuz
parents:
diff changeset
421 const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
422 &*Diagnostics, Compilation.get());
150
anatofuz
parents:
diff changeset
423 if (!CC1Args)
anatofuz
parents:
diff changeset
424 return false;
anatofuz
parents:
diff changeset
425 std::unique_ptr<CompilerInvocation> Invocation(
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
426 newInvocation(&*Diagnostics, *CC1Args, BinaryName));
150
anatofuz
parents:
diff changeset
427 return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
anatofuz
parents:
diff changeset
428 std::move(PCHContainerOps));
anatofuz
parents:
diff changeset
429 }
anatofuz
parents:
diff changeset
430
anatofuz
parents:
diff changeset
431 bool ToolInvocation::runInvocation(
anatofuz
parents:
diff changeset
432 const char *BinaryName, driver::Compilation *Compilation,
anatofuz
parents:
diff changeset
433 std::shared_ptr<CompilerInvocation> Invocation,
anatofuz
parents:
diff changeset
434 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
anatofuz
parents:
diff changeset
435 // Show the invocation, with -v.
anatofuz
parents:
diff changeset
436 if (Invocation->getHeaderSearchOpts().Verbose) {
anatofuz
parents:
diff changeset
437 llvm::errs() << "clang Invocation:\n";
anatofuz
parents:
diff changeset
438 Compilation->getJobs().Print(llvm::errs(), "\n", true);
anatofuz
parents:
diff changeset
439 llvm::errs() << "\n";
anatofuz
parents:
diff changeset
440 }
anatofuz
parents:
diff changeset
441
anatofuz
parents:
diff changeset
442 return Action->runInvocation(std::move(Invocation), Files,
anatofuz
parents:
diff changeset
443 std::move(PCHContainerOps), DiagConsumer);
anatofuz
parents:
diff changeset
444 }
anatofuz
parents:
diff changeset
445
anatofuz
parents:
diff changeset
446 bool FrontendActionFactory::runInvocation(
anatofuz
parents:
diff changeset
447 std::shared_ptr<CompilerInvocation> Invocation, FileManager *Files,
anatofuz
parents:
diff changeset
448 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
anatofuz
parents:
diff changeset
449 DiagnosticConsumer *DiagConsumer) {
anatofuz
parents:
diff changeset
450 // Create a compiler instance to handle the actual work.
anatofuz
parents:
diff changeset
451 CompilerInstance Compiler(std::move(PCHContainerOps));
anatofuz
parents:
diff changeset
452 Compiler.setInvocation(std::move(Invocation));
anatofuz
parents:
diff changeset
453 Compiler.setFileManager(Files);
anatofuz
parents:
diff changeset
454
anatofuz
parents:
diff changeset
455 // The FrontendAction can have lifetime requirements for Compiler or its
anatofuz
parents:
diff changeset
456 // members, and we need to ensure it's deleted earlier than Compiler. So we
anatofuz
parents:
diff changeset
457 // pass it to an std::unique_ptr declared after the Compiler variable.
anatofuz
parents:
diff changeset
458 std::unique_ptr<FrontendAction> ScopedToolAction(create());
anatofuz
parents:
diff changeset
459
anatofuz
parents:
diff changeset
460 // Create the compiler's actual diagnostics engine.
anatofuz
parents:
diff changeset
461 Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
anatofuz
parents:
diff changeset
462 if (!Compiler.hasDiagnostics())
anatofuz
parents:
diff changeset
463 return false;
anatofuz
parents:
diff changeset
464
anatofuz
parents:
diff changeset
465 Compiler.createSourceManager(*Files);
anatofuz
parents:
diff changeset
466
anatofuz
parents:
diff changeset
467 const bool Success = Compiler.ExecuteAction(*ScopedToolAction);
anatofuz
parents:
diff changeset
468
anatofuz
parents:
diff changeset
469 Files->clearStatCache();
anatofuz
parents:
diff changeset
470 return Success;
anatofuz
parents:
diff changeset
471 }
anatofuz
parents:
diff changeset
472
anatofuz
parents:
diff changeset
473 ClangTool::ClangTool(const CompilationDatabase &Compilations,
anatofuz
parents:
diff changeset
474 ArrayRef<std::string> SourcePaths,
anatofuz
parents:
diff changeset
475 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
anatofuz
parents:
diff changeset
476 IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
anatofuz
parents:
diff changeset
477 IntrusiveRefCntPtr<FileManager> Files)
anatofuz
parents:
diff changeset
478 : Compilations(Compilations), SourcePaths(SourcePaths),
anatofuz
parents:
diff changeset
479 PCHContainerOps(std::move(PCHContainerOps)),
anatofuz
parents:
diff changeset
480 OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
anatofuz
parents:
diff changeset
481 InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
anatofuz
parents:
diff changeset
482 Files(Files ? Files
anatofuz
parents:
diff changeset
483 : new FileManager(FileSystemOptions(), OverlayFileSystem)) {
anatofuz
parents:
diff changeset
484 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
anatofuz
parents:
diff changeset
485 appendArgumentsAdjuster(getClangStripOutputAdjuster());
anatofuz
parents:
diff changeset
486 appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
anatofuz
parents:
diff changeset
487 appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
anatofuz
parents:
diff changeset
488 if (Files)
anatofuz
parents:
diff changeset
489 Files->setVirtualFileSystem(OverlayFileSystem);
anatofuz
parents:
diff changeset
490 }
anatofuz
parents:
diff changeset
491
anatofuz
parents:
diff changeset
492 ClangTool::~ClangTool() = default;
anatofuz
parents:
diff changeset
493
anatofuz
parents:
diff changeset
494 void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) {
anatofuz
parents:
diff changeset
495 MappedFileContents.push_back(std::make_pair(FilePath, Content));
anatofuz
parents:
diff changeset
496 }
anatofuz
parents:
diff changeset
497
anatofuz
parents:
diff changeset
498 void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
anatofuz
parents:
diff changeset
499 ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
anatofuz
parents:
diff changeset
500 }
anatofuz
parents:
diff changeset
501
anatofuz
parents:
diff changeset
502 void ClangTool::clearArgumentsAdjusters() {
anatofuz
parents:
diff changeset
503 ArgsAdjuster = nullptr;
anatofuz
parents:
diff changeset
504 }
anatofuz
parents:
diff changeset
505
anatofuz
parents:
diff changeset
506 static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
anatofuz
parents:
diff changeset
507 void *MainAddr) {
anatofuz
parents:
diff changeset
508 // Allow users to override the resource dir.
anatofuz
parents:
diff changeset
509 for (StringRef Arg : Args)
anatofuz
parents:
diff changeset
510 if (Arg.startswith("-resource-dir"))
anatofuz
parents:
diff changeset
511 return;
anatofuz
parents:
diff changeset
512
anatofuz
parents:
diff changeset
513 // If there's no override in place add our resource dir.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
514 Args = getInsertArgumentAdjuster(
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
515 ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr))
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
516 .c_str())(Args, "");
150
anatofuz
parents:
diff changeset
517 }
anatofuz
parents:
diff changeset
518
anatofuz
parents:
diff changeset
519 int ClangTool::run(ToolAction *Action) {
anatofuz
parents:
diff changeset
520 // Exists solely for the purpose of lookup of the resource path.
anatofuz
parents:
diff changeset
521 // This just needs to be some symbol in the binary.
anatofuz
parents:
diff changeset
522 static int StaticSymbol;
anatofuz
parents:
diff changeset
523
anatofuz
parents:
diff changeset
524 // First insert all absolute paths into the in-memory VFS. These are global
anatofuz
parents:
diff changeset
525 // for all compile commands.
anatofuz
parents:
diff changeset
526 if (SeenWorkingDirectories.insert("/").second)
anatofuz
parents:
diff changeset
527 for (const auto &MappedFile : MappedFileContents)
anatofuz
parents:
diff changeset
528 if (llvm::sys::path::is_absolute(MappedFile.first))
anatofuz
parents:
diff changeset
529 InMemoryFileSystem->addFile(
anatofuz
parents:
diff changeset
530 MappedFile.first, 0,
anatofuz
parents:
diff changeset
531 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
anatofuz
parents:
diff changeset
532
anatofuz
parents:
diff changeset
533 bool ProcessingFailed = false;
anatofuz
parents:
diff changeset
534 bool FileSkipped = false;
anatofuz
parents:
diff changeset
535 // Compute all absolute paths before we run any actions, as those will change
anatofuz
parents:
diff changeset
536 // the working directory.
anatofuz
parents:
diff changeset
537 std::vector<std::string> AbsolutePaths;
anatofuz
parents:
diff changeset
538 AbsolutePaths.reserve(SourcePaths.size());
anatofuz
parents:
diff changeset
539 for (const auto &SourcePath : SourcePaths) {
anatofuz
parents:
diff changeset
540 auto AbsPath = getAbsolutePath(*OverlayFileSystem, SourcePath);
anatofuz
parents:
diff changeset
541 if (!AbsPath) {
anatofuz
parents:
diff changeset
542 llvm::errs() << "Skipping " << SourcePath
anatofuz
parents:
diff changeset
543 << ". Error while getting an absolute path: "
anatofuz
parents:
diff changeset
544 << llvm::toString(AbsPath.takeError()) << "\n";
anatofuz
parents:
diff changeset
545 continue;
anatofuz
parents:
diff changeset
546 }
anatofuz
parents:
diff changeset
547 AbsolutePaths.push_back(std::move(*AbsPath));
anatofuz
parents:
diff changeset
548 }
anatofuz
parents:
diff changeset
549
anatofuz
parents:
diff changeset
550 // Remember the working directory in case we need to restore it.
anatofuz
parents:
diff changeset
551 std::string InitialWorkingDir;
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
552 if (auto CWD = OverlayFileSystem->getCurrentWorkingDirectory()) {
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
553 InitialWorkingDir = std::move(*CWD);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
554 } else {
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
555 llvm::errs() << "Could not get working directory: "
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
556 << CWD.getError().message() << "\n";
150
anatofuz
parents:
diff changeset
557 }
anatofuz
parents:
diff changeset
558
anatofuz
parents:
diff changeset
559 for (llvm::StringRef File : AbsolutePaths) {
anatofuz
parents:
diff changeset
560 // Currently implementations of CompilationDatabase::getCompileCommands can
anatofuz
parents:
diff changeset
561 // change the state of the file system (e.g. prepare generated headers), so
anatofuz
parents:
diff changeset
562 // this method needs to run right before we invoke the tool, as the next
anatofuz
parents:
diff changeset
563 // file may require a different (incompatible) state of the file system.
anatofuz
parents:
diff changeset
564 //
anatofuz
parents:
diff changeset
565 // FIXME: Make the compilation database interface more explicit about the
anatofuz
parents:
diff changeset
566 // requirements to the order of invocation of its members.
anatofuz
parents:
diff changeset
567 std::vector<CompileCommand> CompileCommandsForFile =
anatofuz
parents:
diff changeset
568 Compilations.getCompileCommands(File);
anatofuz
parents:
diff changeset
569 if (CompileCommandsForFile.empty()) {
anatofuz
parents:
diff changeset
570 llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
anatofuz
parents:
diff changeset
571 FileSkipped = true;
anatofuz
parents:
diff changeset
572 continue;
anatofuz
parents:
diff changeset
573 }
anatofuz
parents:
diff changeset
574 for (CompileCommand &CompileCommand : CompileCommandsForFile) {
anatofuz
parents:
diff changeset
575 // FIXME: chdir is thread hostile; on the other hand, creating the same
anatofuz
parents:
diff changeset
576 // behavior as chdir is complex: chdir resolves the path once, thus
anatofuz
parents:
diff changeset
577 // guaranteeing that all subsequent relative path operations work
anatofuz
parents:
diff changeset
578 // on the same path the original chdir resulted in. This makes a
anatofuz
parents:
diff changeset
579 // difference for example on network filesystems, where symlinks might be
anatofuz
parents:
diff changeset
580 // switched during runtime of the tool. Fixing this depends on having a
anatofuz
parents:
diff changeset
581 // file system abstraction that allows openat() style interactions.
anatofuz
parents:
diff changeset
582 if (OverlayFileSystem->setCurrentWorkingDirectory(
anatofuz
parents:
diff changeset
583 CompileCommand.Directory))
anatofuz
parents:
diff changeset
584 llvm::report_fatal_error("Cannot chdir into \"" +
anatofuz
parents:
diff changeset
585 Twine(CompileCommand.Directory) + "\"!");
anatofuz
parents:
diff changeset
586
anatofuz
parents:
diff changeset
587 // Now fill the in-memory VFS with the relative file mappings so it will
anatofuz
parents:
diff changeset
588 // have the correct relative paths. We never remove mappings but that
anatofuz
parents:
diff changeset
589 // should be fine.
anatofuz
parents:
diff changeset
590 if (SeenWorkingDirectories.insert(CompileCommand.Directory).second)
anatofuz
parents:
diff changeset
591 for (const auto &MappedFile : MappedFileContents)
anatofuz
parents:
diff changeset
592 if (!llvm::sys::path::is_absolute(MappedFile.first))
anatofuz
parents:
diff changeset
593 InMemoryFileSystem->addFile(
anatofuz
parents:
diff changeset
594 MappedFile.first, 0,
anatofuz
parents:
diff changeset
595 llvm::MemoryBuffer::getMemBuffer(MappedFile.second));
anatofuz
parents:
diff changeset
596
anatofuz
parents:
diff changeset
597 std::vector<std::string> CommandLine = CompileCommand.CommandLine;
anatofuz
parents:
diff changeset
598 if (ArgsAdjuster)
anatofuz
parents:
diff changeset
599 CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename);
anatofuz
parents:
diff changeset
600 assert(!CommandLine.empty());
anatofuz
parents:
diff changeset
601
anatofuz
parents:
diff changeset
602 // Add the resource dir based on the binary of this tool. argv[0] in the
anatofuz
parents:
diff changeset
603 // compilation database may refer to a different compiler and we want to
anatofuz
parents:
diff changeset
604 // pick up the very same standard library that compiler is using. The
anatofuz
parents:
diff changeset
605 // builtin headers in the resource dir need to match the exact clang
anatofuz
parents:
diff changeset
606 // version the tool is using.
anatofuz
parents:
diff changeset
607 // FIXME: On linux, GetMainExecutable is independent of the value of the
anatofuz
parents:
diff changeset
608 // first argument, thus allowing ClangTool and runToolOnCode to just
anatofuz
parents:
diff changeset
609 // pass in made-up names here. Make sure this works on other platforms.
anatofuz
parents:
diff changeset
610 injectResourceDir(CommandLine, "clang_tool", &StaticSymbol);
anatofuz
parents:
diff changeset
611
anatofuz
parents:
diff changeset
612 // FIXME: We need a callback mechanism for the tool writer to output a
anatofuz
parents:
diff changeset
613 // customized message for each file.
anatofuz
parents:
diff changeset
614 LLVM_DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
anatofuz
parents:
diff changeset
615 ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
anatofuz
parents:
diff changeset
616 PCHContainerOps);
anatofuz
parents:
diff changeset
617 Invocation.setDiagnosticConsumer(DiagConsumer);
anatofuz
parents:
diff changeset
618
anatofuz
parents:
diff changeset
619 if (!Invocation.run()) {
anatofuz
parents:
diff changeset
620 // FIXME: Diagnostics should be used instead.
anatofuz
parents:
diff changeset
621 if (PrintErrorMessage)
anatofuz
parents:
diff changeset
622 llvm::errs() << "Error while processing " << File << ".\n";
anatofuz
parents:
diff changeset
623 ProcessingFailed = true;
anatofuz
parents:
diff changeset
624 }
anatofuz
parents:
diff changeset
625 }
anatofuz
parents:
diff changeset
626 }
anatofuz
parents:
diff changeset
627
anatofuz
parents:
diff changeset
628 if (!InitialWorkingDir.empty()) {
anatofuz
parents:
diff changeset
629 if (auto EC =
anatofuz
parents:
diff changeset
630 OverlayFileSystem->setCurrentWorkingDirectory(InitialWorkingDir))
anatofuz
parents:
diff changeset
631 llvm::errs() << "Error when trying to restore working dir: "
anatofuz
parents:
diff changeset
632 << EC.message() << "\n";
anatofuz
parents:
diff changeset
633 }
anatofuz
parents:
diff changeset
634 return ProcessingFailed ? 1 : (FileSkipped ? 2 : 0);
anatofuz
parents:
diff changeset
635 }
anatofuz
parents:
diff changeset
636
anatofuz
parents:
diff changeset
637 namespace {
anatofuz
parents:
diff changeset
638
anatofuz
parents:
diff changeset
639 class ASTBuilderAction : public ToolAction {
anatofuz
parents:
diff changeset
640 std::vector<std::unique_ptr<ASTUnit>> &ASTs;
anatofuz
parents:
diff changeset
641
anatofuz
parents:
diff changeset
642 public:
anatofuz
parents:
diff changeset
643 ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
anatofuz
parents:
diff changeset
644
anatofuz
parents:
diff changeset
645 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
anatofuz
parents:
diff changeset
646 FileManager *Files,
anatofuz
parents:
diff changeset
647 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
anatofuz
parents:
diff changeset
648 DiagnosticConsumer *DiagConsumer) override {
anatofuz
parents:
diff changeset
649 std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
anatofuz
parents:
diff changeset
650 Invocation, std::move(PCHContainerOps),
anatofuz
parents:
diff changeset
651 CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
anatofuz
parents:
diff changeset
652 DiagConsumer,
anatofuz
parents:
diff changeset
653 /*ShouldOwnClient=*/false),
anatofuz
parents:
diff changeset
654 Files);
anatofuz
parents:
diff changeset
655 if (!AST)
anatofuz
parents:
diff changeset
656 return false;
anatofuz
parents:
diff changeset
657
anatofuz
parents:
diff changeset
658 ASTs.push_back(std::move(AST));
anatofuz
parents:
diff changeset
659 return true;
anatofuz
parents:
diff changeset
660 }
anatofuz
parents:
diff changeset
661 };
anatofuz
parents:
diff changeset
662
anatofuz
parents:
diff changeset
663 } // namespace
anatofuz
parents:
diff changeset
664
anatofuz
parents:
diff changeset
665 int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
anatofuz
parents:
diff changeset
666 ASTBuilderAction Action(ASTs);
anatofuz
parents:
diff changeset
667 return run(&Action);
anatofuz
parents:
diff changeset
668 }
anatofuz
parents:
diff changeset
669
anatofuz
parents:
diff changeset
670 void ClangTool::setPrintErrorMessage(bool PrintErrorMessage) {
anatofuz
parents:
diff changeset
671 this->PrintErrorMessage = PrintErrorMessage;
anatofuz
parents:
diff changeset
672 }
anatofuz
parents:
diff changeset
673
anatofuz
parents:
diff changeset
674 namespace clang {
anatofuz
parents:
diff changeset
675 namespace tooling {
anatofuz
parents:
diff changeset
676
anatofuz
parents:
diff changeset
677 std::unique_ptr<ASTUnit>
anatofuz
parents:
diff changeset
678 buildASTFromCode(StringRef Code, StringRef FileName,
anatofuz
parents:
diff changeset
679 std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
anatofuz
parents:
diff changeset
680 return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName,
anatofuz
parents:
diff changeset
681 "clang-tool", std::move(PCHContainerOps));
anatofuz
parents:
diff changeset
682 }
anatofuz
parents:
diff changeset
683
anatofuz
parents:
diff changeset
684 std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
anatofuz
parents:
diff changeset
685 StringRef Code, const std::vector<std::string> &Args, StringRef FileName,
anatofuz
parents:
diff changeset
686 StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
687 ArgumentsAdjuster Adjuster, const FileContentMappings &VirtualMappedFiles,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
688 DiagnosticConsumer *DiagConsumer) {
150
anatofuz
parents:
diff changeset
689 std::vector<std::unique_ptr<ASTUnit>> ASTs;
anatofuz
parents:
diff changeset
690 ASTBuilderAction Action(ASTs);
anatofuz
parents:
diff changeset
691 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
anatofuz
parents:
diff changeset
692 new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
anatofuz
parents:
diff changeset
693 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
anatofuz
parents:
diff changeset
694 new llvm::vfs::InMemoryFileSystem);
anatofuz
parents:
diff changeset
695 OverlayFileSystem->pushOverlay(InMemoryFileSystem);
anatofuz
parents:
diff changeset
696 llvm::IntrusiveRefCntPtr<FileManager> Files(
anatofuz
parents:
diff changeset
697 new FileManager(FileSystemOptions(), OverlayFileSystem));
anatofuz
parents:
diff changeset
698
anatofuz
parents:
diff changeset
699 ToolInvocation Invocation(
anatofuz
parents:
diff changeset
700 getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName),
anatofuz
parents:
diff changeset
701 &Action, Files.get(), std::move(PCHContainerOps));
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
702 Invocation.setDiagnosticConsumer(DiagConsumer);
150
anatofuz
parents:
diff changeset
703
anatofuz
parents:
diff changeset
704 InMemoryFileSystem->addFile(FileName, 0,
anatofuz
parents:
diff changeset
705 llvm::MemoryBuffer::getMemBufferCopy(Code));
anatofuz
parents:
diff changeset
706 for (auto &FilenameWithContent : VirtualMappedFiles) {
anatofuz
parents:
diff changeset
707 InMemoryFileSystem->addFile(
anatofuz
parents:
diff changeset
708 FilenameWithContent.first, 0,
anatofuz
parents:
diff changeset
709 llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
anatofuz
parents:
diff changeset
710 }
anatofuz
parents:
diff changeset
711
anatofuz
parents:
diff changeset
712 if (!Invocation.run())
anatofuz
parents:
diff changeset
713 return nullptr;
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
714
150
anatofuz
parents:
diff changeset
715 assert(ASTs.size() == 1);
anatofuz
parents:
diff changeset
716 return std::move(ASTs[0]);
anatofuz
parents:
diff changeset
717 }
anatofuz
parents:
diff changeset
718
anatofuz
parents:
diff changeset
719 } // namespace tooling
anatofuz
parents:
diff changeset
720 } // namespace clang