File: | tools/clang/lib/Tooling/Tooling.cpp |
Warning: | line 157, column 38 Potential leak of memory pointed to by field 'Obj' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- Tooling.cpp - Running clang standalone tools -----------------------===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file implements functions to run clang tools standalone instead | |||
11 | // of running them as a plugin. | |||
12 | // | |||
13 | //===----------------------------------------------------------------------===// | |||
14 | ||||
15 | #include "clang/Tooling/Tooling.h" | |||
16 | #include "clang/Basic/Diagnostic.h" | |||
17 | #include "clang/Basic/DiagnosticIDs.h" | |||
18 | #include "clang/Basic/DiagnosticOptions.h" | |||
19 | #include "clang/Basic/FileManager.h" | |||
20 | #include "clang/Basic/FileSystemOptions.h" | |||
21 | #include "clang/Basic/LLVM.h" | |||
22 | #include "clang/Basic/VirtualFileSystem.h" | |||
23 | #include "clang/Driver/Compilation.h" | |||
24 | #include "clang/Driver/Driver.h" | |||
25 | #include "clang/Driver/Job.h" | |||
26 | #include "clang/Driver/Options.h" | |||
27 | #include "clang/Driver/Tool.h" | |||
28 | #include "clang/Driver/ToolChain.h" | |||
29 | #include "clang/Frontend/ASTUnit.h" | |||
30 | #include "clang/Frontend/CompilerInstance.h" | |||
31 | #include "clang/Frontend/CompilerInvocation.h" | |||
32 | #include "clang/Frontend/FrontendDiagnostic.h" | |||
33 | #include "clang/Frontend/FrontendOptions.h" | |||
34 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |||
35 | #include "clang/Lex/HeaderSearchOptions.h" | |||
36 | #include "clang/Lex/PreprocessorOptions.h" | |||
37 | #include "clang/Tooling/ArgumentsAdjusters.h" | |||
38 | #include "clang/Tooling/CompilationDatabase.h" | |||
39 | #include "llvm/ADT/ArrayRef.h" | |||
40 | #include "llvm/ADT/IntrusiveRefCntPtr.h" | |||
41 | #include "llvm/ADT/SmallString.h" | |||
42 | #include "llvm/ADT/StringRef.h" | |||
43 | #include "llvm/ADT/Twine.h" | |||
44 | #include "llvm/Config/llvm-config.h" | |||
45 | #include "llvm/Option/ArgList.h" | |||
46 | #include "llvm/Option/OptTable.h" | |||
47 | #include "llvm/Option/Option.h" | |||
48 | #include "llvm/Support/Casting.h" | |||
49 | #include "llvm/Support/Debug.h" | |||
50 | #include "llvm/Support/ErrorHandling.h" | |||
51 | #include "llvm/Support/FileSystem.h" | |||
52 | #include "llvm/Support/Host.h" | |||
53 | #include "llvm/Support/MemoryBuffer.h" | |||
54 | #include "llvm/Support/Path.h" | |||
55 | #include "llvm/Support/raw_ostream.h" | |||
56 | #include <cassert> | |||
57 | #include <cstring> | |||
58 | #include <memory> | |||
59 | #include <string> | |||
60 | #include <system_error> | |||
61 | #include <utility> | |||
62 | #include <vector> | |||
63 | ||||
64 | #define DEBUG_TYPE"clang-tooling" "clang-tooling" | |||
65 | ||||
66 | using namespace clang; | |||
67 | using namespace tooling; | |||
68 | ||||
69 | ToolAction::~ToolAction() = default; | |||
70 | ||||
71 | FrontendActionFactory::~FrontendActionFactory() = default; | |||
72 | ||||
73 | // FIXME: This file contains structural duplication with other parts of the | |||
74 | // code that sets up a compiler to run tools on it, and we should refactor | |||
75 | // it to be based on the same framework. | |||
76 | ||||
77 | /// \brief Builds a clang driver initialized for running clang tools. | |||
78 | static driver::Driver *newDriver( | |||
79 | DiagnosticsEngine *Diagnostics, const char *BinaryName, | |||
80 | IntrusiveRefCntPtr<vfs::FileSystem> VFS) { | |||
81 | driver::Driver *CompilerDriver = | |||
82 | new driver::Driver(BinaryName, llvm::sys::getDefaultTargetTriple(), | |||
83 | *Diagnostics, std::move(VFS)); | |||
84 | CompilerDriver->setTitle("clang_based_tool"); | |||
85 | return CompilerDriver; | |||
86 | } | |||
87 | ||||
88 | /// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs. | |||
89 | /// | |||
90 | /// Returns nullptr on error. | |||
91 | static const llvm::opt::ArgStringList *getCC1Arguments( | |||
92 | DiagnosticsEngine *Diagnostics, driver::Compilation *Compilation) { | |||
93 | // We expect to get back exactly one Command job, if we didn't something | |||
94 | // failed. Extract that job from the Compilation. | |||
95 | const driver::JobList &Jobs = Compilation->getJobs(); | |||
96 | if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) { | |||
97 | SmallString<256> error_msg; | |||
98 | llvm::raw_svector_ostream error_stream(error_msg); | |||
99 | Jobs.Print(error_stream, "; ", true); | |||
100 | Diagnostics->Report(diag::err_fe_expected_compiler_job) | |||
101 | << error_stream.str(); | |||
102 | return nullptr; | |||
103 | } | |||
104 | ||||
105 | // The one job we find should be to invoke clang again. | |||
106 | const auto &Cmd = cast<driver::Command>(*Jobs.begin()); | |||
107 | if (StringRef(Cmd.getCreator().getName()) != "clang") { | |||
108 | Diagnostics->Report(diag::err_fe_expected_clang_command); | |||
109 | return nullptr; | |||
110 | } | |||
111 | ||||
112 | return &Cmd.getArguments(); | |||
113 | } | |||
114 | ||||
115 | namespace clang { | |||
116 | namespace tooling { | |||
117 | ||||
118 | /// \brief Returns a clang build invocation initialized from the CC1 flags. | |||
119 | CompilerInvocation *newInvocation( | |||
120 | DiagnosticsEngine *Diagnostics, const llvm::opt::ArgStringList &CC1Args) { | |||
121 | assert(!CC1Args.empty() && "Must at least contain the program name!")(static_cast <bool> (!CC1Args.empty() && "Must at least contain the program name!" ) ? void (0) : __assert_fail ("!CC1Args.empty() && \"Must at least contain the program name!\"" , "/build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/Tooling/Tooling.cpp" , 121, __extension__ __PRETTY_FUNCTION__)); | |||
122 | CompilerInvocation *Invocation = new CompilerInvocation; | |||
123 | CompilerInvocation::CreateFromArgs( | |||
124 | *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(), | |||
125 | *Diagnostics); | |||
126 | Invocation->getFrontendOpts().DisableFree = false; | |||
127 | Invocation->getCodeGenOpts().DisableFree = false; | |||
128 | return Invocation; | |||
129 | } | |||
130 | ||||
131 | bool runToolOnCode(FrontendAction *ToolAction, const Twine &Code, | |||
132 | const Twine &FileName, | |||
133 | std::shared_ptr<PCHContainerOperations> PCHContainerOps) { | |||
134 | return runToolOnCodeWithArgs(ToolAction, Code, std::vector<std::string>(), | |||
135 | FileName, "clang-tool", | |||
136 | std::move(PCHContainerOps)); | |||
137 | } | |||
138 | ||||
139 | } // namespace tooling | |||
140 | } // namespace clang | |||
141 | ||||
142 | static std::vector<std::string> | |||
143 | getSyntaxOnlyToolArgs(const Twine &ToolName, | |||
144 | const std::vector<std::string> &ExtraArgs, | |||
145 | StringRef FileName) { | |||
146 | std::vector<std::string> Args; | |||
147 | Args.push_back(ToolName.str()); | |||
148 | Args.push_back("-fsyntax-only"); | |||
149 | Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end()); | |||
150 | Args.push_back(FileName.str()); | |||
151 | return Args; | |||
152 | } | |||
153 | ||||
154 | namespace clang { | |||
155 | namespace tooling { | |||
156 | ||||
157 | bool runToolOnCodeWithArgs( | |||
158 | FrontendAction *ToolAction, const Twine &Code, | |||
159 | const std::vector<std::string> &Args, const Twine &FileName, | |||
160 | const Twine &ToolName, | |||
161 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
162 | const FileContentMappings &VirtualMappedFiles) { | |||
163 | SmallString<16> FileNameStorage; | |||
164 | StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); | |||
165 | llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( | |||
166 | new vfs::OverlayFileSystem(vfs::getRealFileSystem())); | |||
167 | llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( | |||
168 | new vfs::InMemoryFileSystem); | |||
169 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); | |||
170 | llvm::IntrusiveRefCntPtr<FileManager> Files( | |||
171 | new FileManager(FileSystemOptions(), OverlayFileSystem)); | |||
172 | ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(); | |||
173 | ToolInvocation Invocation( | |||
174 | getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), | |||
175 | ToolAction, Files.get(), | |||
176 | std::move(PCHContainerOps)); | |||
177 | ||||
178 | SmallString<1024> CodeStorage; | |||
179 | InMemoryFileSystem->addFile(FileNameRef, 0, | |||
180 | llvm::MemoryBuffer::getMemBuffer( | |||
181 | Code.toNullTerminatedStringRef(CodeStorage))); | |||
182 | ||||
183 | for (auto &FilenameWithContent : VirtualMappedFiles) { | |||
184 | InMemoryFileSystem->addFile( | |||
185 | FilenameWithContent.first, 0, | |||
186 | llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second)); | |||
187 | } | |||
188 | ||||
189 | return Invocation.run(); | |||
190 | } | |||
191 | ||||
192 | std::string getAbsolutePath(StringRef File) { | |||
193 | StringRef RelativePath(File); | |||
194 | // FIXME: Should '.\\' be accepted on Win32? | |||
195 | if (RelativePath.startswith("./")) { | |||
196 | RelativePath = RelativePath.substr(strlen("./")); | |||
197 | } | |||
198 | ||||
199 | SmallString<1024> AbsolutePath = RelativePath; | |||
200 | std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath); | |||
201 | assert(!EC)(static_cast <bool> (!EC) ? void (0) : __assert_fail ("!EC" , "/build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/Tooling/Tooling.cpp" , 201, __extension__ __PRETTY_FUNCTION__)); | |||
202 | (void)EC; | |||
203 | llvm::sys::path::native(AbsolutePath); | |||
204 | return AbsolutePath.str(); | |||
205 | } | |||
206 | ||||
207 | void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine, | |||
208 | StringRef InvokedAs) { | |||
209 | if (!CommandLine.empty() && !InvokedAs.empty()) { | |||
210 | bool AlreadyHasTarget = false; | |||
211 | bool AlreadyHasMode = false; | |||
212 | // Skip CommandLine[0]. | |||
213 | for (auto Token = ++CommandLine.begin(); Token != CommandLine.end(); | |||
214 | ++Token) { | |||
215 | StringRef TokenRef(*Token); | |||
216 | AlreadyHasTarget |= | |||
217 | (TokenRef == "-target" || TokenRef.startswith("-target=")); | |||
218 | AlreadyHasMode |= (TokenRef == "--driver-mode" || | |||
219 | TokenRef.startswith("--driver-mode=")); | |||
220 | } | |||
221 | auto TargetMode = | |||
222 | driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs); | |||
223 | if (!AlreadyHasMode && TargetMode.DriverMode) { | |||
224 | CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode); | |||
225 | } | |||
226 | if (!AlreadyHasTarget && TargetMode.TargetIsValid) { | |||
227 | CommandLine.insert(++CommandLine.begin(), {"-target", | |||
228 | TargetMode.TargetPrefix}); | |||
229 | } | |||
230 | } | |||
231 | } | |||
232 | ||||
233 | } // namespace tooling | |||
234 | } // namespace clang | |||
235 | ||||
236 | namespace { | |||
237 | ||||
238 | class SingleFrontendActionFactory : public FrontendActionFactory { | |||
239 | FrontendAction *Action; | |||
240 | ||||
241 | public: | |||
242 | SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {} | |||
243 | ||||
244 | FrontendAction *create() override { return Action; } | |||
245 | }; | |||
246 | ||||
247 | } // namespace | |||
248 | ||||
249 | ToolInvocation::ToolInvocation( | |||
250 | std::vector<std::string> CommandLine, ToolAction *Action, | |||
251 | FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps) | |||
252 | : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(false), | |||
253 | Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {} | |||
254 | ||||
255 | ToolInvocation::ToolInvocation( | |||
256 | std::vector<std::string> CommandLine, FrontendAction *FAction, | |||
257 | FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps) | |||
258 | : CommandLine(std::move(CommandLine)), | |||
259 | Action(new SingleFrontendActionFactory(FAction)), OwnsAction(true), | |||
260 | Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {} | |||
261 | ||||
262 | ToolInvocation::~ToolInvocation() { | |||
263 | if (OwnsAction) | |||
264 | delete Action; | |||
265 | } | |||
266 | ||||
267 | void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) { | |||
268 | SmallString<1024> PathStorage; | |||
269 | llvm::sys::path::native(FilePath, PathStorage); | |||
270 | MappedFileContents[PathStorage] = Content; | |||
271 | } | |||
272 | ||||
273 | bool ToolInvocation::run() { | |||
274 | std::vector<const char*> Argv; | |||
275 | for (const std::string &Str : CommandLine) | |||
276 | Argv.push_back(Str.c_str()); | |||
277 | const char *const BinaryName = Argv[0]; | |||
278 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); | |||
279 | unsigned MissingArgIndex, MissingArgCount; | |||
280 | std::unique_ptr<llvm::opt::OptTable> Opts = driver::createDriverOptTable(); | |||
281 | llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs( | |||
282 | ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount); | |||
283 | ParseDiagnosticArgs(*DiagOpts, ParsedArgs); | |||
284 | TextDiagnosticPrinter DiagnosticPrinter( | |||
285 | llvm::errs(), &*DiagOpts); | |||
286 | DiagnosticsEngine Diagnostics( | |||
287 | IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, | |||
288 | DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); | |||
289 | ||||
290 | const std::unique_ptr<driver::Driver> Driver( | |||
291 | newDriver(&Diagnostics, BinaryName, Files->getVirtualFileSystem())); | |||
292 | // Since the input might only be virtual, don't check whether it exists. | |||
293 | Driver->setCheckInputsExist(false); | |||
294 | const std::unique_ptr<driver::Compilation> Compilation( | |||
295 | Driver->BuildCompilation(llvm::makeArrayRef(Argv))); | |||
296 | if (!Compilation) | |||
297 | return false; | |||
298 | const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments( | |||
299 | &Diagnostics, Compilation.get()); | |||
300 | if (!CC1Args) | |||
301 | return false; | |||
302 | std::unique_ptr<CompilerInvocation> Invocation( | |||
303 | newInvocation(&Diagnostics, *CC1Args)); | |||
304 | // FIXME: remove this when all users have migrated! | |||
305 | for (const auto &It : MappedFileContents) { | |||
306 | // Inject the code as the given file name into the preprocessor options. | |||
307 | std::unique_ptr<llvm::MemoryBuffer> Input = | |||
308 | llvm::MemoryBuffer::getMemBuffer(It.getValue()); | |||
309 | Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(), | |||
310 | Input.release()); | |||
311 | } | |||
312 | return runInvocation(BinaryName, Compilation.get(), std::move(Invocation), | |||
313 | std::move(PCHContainerOps)); | |||
314 | } | |||
315 | ||||
316 | bool ToolInvocation::runInvocation( | |||
317 | const char *BinaryName, driver::Compilation *Compilation, | |||
318 | std::shared_ptr<CompilerInvocation> Invocation, | |||
319 | std::shared_ptr<PCHContainerOperations> PCHContainerOps) { | |||
320 | // Show the invocation, with -v. | |||
321 | if (Invocation->getHeaderSearchOpts().Verbose) { | |||
322 | llvm::errs() << "clang Invocation:\n"; | |||
323 | Compilation->getJobs().Print(llvm::errs(), "\n", true); | |||
324 | llvm::errs() << "\n"; | |||
325 | } | |||
326 | ||||
327 | return Action->runInvocation(std::move(Invocation), Files, | |||
328 | std::move(PCHContainerOps), DiagConsumer); | |||
329 | } | |||
330 | ||||
331 | bool FrontendActionFactory::runInvocation( | |||
332 | std::shared_ptr<CompilerInvocation> Invocation, FileManager *Files, | |||
333 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
334 | DiagnosticConsumer *DiagConsumer) { | |||
335 | // Create a compiler instance to handle the actual work. | |||
336 | CompilerInstance Compiler(std::move(PCHContainerOps)); | |||
337 | Compiler.setInvocation(std::move(Invocation)); | |||
338 | Compiler.setFileManager(Files); | |||
339 | ||||
340 | // The FrontendAction can have lifetime requirements for Compiler or its | |||
341 | // members, and we need to ensure it's deleted earlier than Compiler. So we | |||
342 | // pass it to an std::unique_ptr declared after the Compiler variable. | |||
343 | std::unique_ptr<FrontendAction> ScopedToolAction(create()); | |||
344 | ||||
345 | // Create the compiler's actual diagnostics engine. | |||
346 | Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); | |||
347 | if (!Compiler.hasDiagnostics()) | |||
348 | return false; | |||
349 | ||||
350 | Compiler.createSourceManager(*Files); | |||
351 | ||||
352 | const bool Success = Compiler.ExecuteAction(*ScopedToolAction); | |||
353 | ||||
354 | Files->clearStatCaches(); | |||
355 | return Success; | |||
356 | } | |||
357 | ||||
358 | ClangTool::ClangTool(const CompilationDatabase &Compilations, | |||
359 | ArrayRef<std::string> SourcePaths, | |||
360 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
361 | IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) | |||
362 | : Compilations(Compilations), SourcePaths(SourcePaths), | |||
363 | PCHContainerOps(std::move(PCHContainerOps)), | |||
364 | OverlayFileSystem(new vfs::OverlayFileSystem(std::move(BaseFS))), | |||
365 | InMemoryFileSystem(new vfs::InMemoryFileSystem), | |||
366 | Files(new FileManager(FileSystemOptions(), OverlayFileSystem)) { | |||
367 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); | |||
368 | appendArgumentsAdjuster(getClangStripOutputAdjuster()); | |||
369 | appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); | |||
370 | appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); | |||
371 | } | |||
372 | ||||
373 | ClangTool::~ClangTool() = default; | |||
374 | ||||
375 | void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) { | |||
376 | MappedFileContents.push_back(std::make_pair(FilePath, Content)); | |||
377 | } | |||
378 | ||||
379 | void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) { | |||
380 | ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster)); | |||
381 | } | |||
382 | ||||
383 | void ClangTool::clearArgumentsAdjusters() { | |||
384 | ArgsAdjuster = nullptr; | |||
385 | } | |||
386 | ||||
387 | static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, | |||
388 | void *MainAddr) { | |||
389 | // Allow users to override the resource dir. | |||
390 | for (StringRef Arg : Args) | |||
391 | if (Arg.startswith("-resource-dir")) | |||
392 | return; | |||
393 | ||||
394 | // If there's no override in place add our resource dir. | |||
395 | Args.push_back("-resource-dir=" + | |||
396 | CompilerInvocation::GetResourcesPath(Argv0, MainAddr)); | |||
397 | } | |||
398 | ||||
399 | int ClangTool::run(ToolAction *Action) { | |||
400 | // Exists solely for the purpose of lookup of the resource path. | |||
401 | // This just needs to be some symbol in the binary. | |||
402 | static int StaticSymbol; | |||
403 | ||||
404 | llvm::SmallString<128> InitialDirectory; | |||
405 | if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory)) | |||
406 | llvm::report_fatal_error("Cannot detect current path: " + | |||
407 | Twine(EC.message())); | |||
408 | ||||
409 | // First insert all absolute paths into the in-memory VFS. These are global | |||
410 | // for all compile commands. | |||
411 | if (SeenWorkingDirectories.insert("/").second) | |||
412 | for (const auto &MappedFile : MappedFileContents) | |||
413 | if (llvm::sys::path::is_absolute(MappedFile.first)) | |||
414 | InMemoryFileSystem->addFile( | |||
415 | MappedFile.first, 0, | |||
416 | llvm::MemoryBuffer::getMemBuffer(MappedFile.second)); | |||
417 | ||||
418 | bool ProcessingFailed = false; | |||
419 | bool FileSkipped = false; | |||
420 | for (const auto &SourcePath : SourcePaths) { | |||
421 | std::string File(getAbsolutePath(SourcePath)); | |||
422 | ||||
423 | // Currently implementations of CompilationDatabase::getCompileCommands can | |||
424 | // change the state of the file system (e.g. prepare generated headers), so | |||
425 | // this method needs to run right before we invoke the tool, as the next | |||
426 | // file may require a different (incompatible) state of the file system. | |||
427 | // | |||
428 | // FIXME: Make the compilation database interface more explicit about the | |||
429 | // requirements to the order of invocation of its members. | |||
430 | std::vector<CompileCommand> CompileCommandsForFile = | |||
431 | Compilations.getCompileCommands(File); | |||
432 | if (CompileCommandsForFile.empty()) { | |||
433 | llvm::errs() << "Skipping " << File << ". Compile command not found.\n"; | |||
434 | FileSkipped = true; | |||
435 | continue; | |||
436 | } | |||
437 | for (CompileCommand &CompileCommand : CompileCommandsForFile) { | |||
438 | // FIXME: chdir is thread hostile; on the other hand, creating the same | |||
439 | // behavior as chdir is complex: chdir resolves the path once, thus | |||
440 | // guaranteeing that all subsequent relative path operations work | |||
441 | // on the same path the original chdir resulted in. This makes a | |||
442 | // difference for example on network filesystems, where symlinks might be | |||
443 | // switched during runtime of the tool. Fixing this depends on having a | |||
444 | // file system abstraction that allows openat() style interactions. | |||
445 | if (OverlayFileSystem->setCurrentWorkingDirectory( | |||
446 | CompileCommand.Directory)) | |||
447 | llvm::report_fatal_error("Cannot chdir into \"" + | |||
448 | Twine(CompileCommand.Directory) + "\n!"); | |||
449 | ||||
450 | // Now fill the in-memory VFS with the relative file mappings so it will | |||
451 | // have the correct relative paths. We never remove mappings but that | |||
452 | // should be fine. | |||
453 | if (SeenWorkingDirectories.insert(CompileCommand.Directory).second) | |||
454 | for (const auto &MappedFile : MappedFileContents) | |||
455 | if (!llvm::sys::path::is_absolute(MappedFile.first)) | |||
456 | InMemoryFileSystem->addFile( | |||
457 | MappedFile.first, 0, | |||
458 | llvm::MemoryBuffer::getMemBuffer(MappedFile.second)); | |||
459 | ||||
460 | std::vector<std::string> CommandLine = CompileCommand.CommandLine; | |||
461 | if (ArgsAdjuster) | |||
462 | CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename); | |||
463 | assert(!CommandLine.empty())(static_cast <bool> (!CommandLine.empty()) ? void (0) : __assert_fail ("!CommandLine.empty()", "/build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/Tooling/Tooling.cpp" , 463, __extension__ __PRETTY_FUNCTION__)); | |||
464 | ||||
465 | // Add the resource dir based on the binary of this tool. argv[0] in the | |||
466 | // compilation database may refer to a different compiler and we want to | |||
467 | // pick up the very same standard library that compiler is using. The | |||
468 | // builtin headers in the resource dir need to match the exact clang | |||
469 | // version the tool is using. | |||
470 | // FIXME: On linux, GetMainExecutable is independent of the value of the | |||
471 | // first argument, thus allowing ClangTool and runToolOnCode to just | |||
472 | // pass in made-up names here. Make sure this works on other platforms. | |||
473 | injectResourceDir(CommandLine, "clang_tool", &StaticSymbol); | |||
474 | ||||
475 | // FIXME: We need a callback mechanism for the tool writer to output a | |||
476 | // customized message for each file. | |||
477 | DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("clang-tooling")) { { llvm::dbgs() << "Processing: " << File << ".\n"; }; } } while (false); | |||
478 | ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(), | |||
479 | PCHContainerOps); | |||
480 | Invocation.setDiagnosticConsumer(DiagConsumer); | |||
481 | ||||
482 | if (!Invocation.run()) { | |||
483 | // FIXME: Diagnostics should be used instead. | |||
484 | llvm::errs() << "Error while processing " << File << ".\n"; | |||
485 | ProcessingFailed = true; | |||
486 | } | |||
487 | // Return to the initial directory to correctly resolve next file by | |||
488 | // relative path. | |||
489 | if (OverlayFileSystem->setCurrentWorkingDirectory(InitialDirectory.c_str())) | |||
490 | llvm::report_fatal_error("Cannot chdir into \"" + | |||
491 | Twine(InitialDirectory) + "\n!"); | |||
492 | } | |||
493 | } | |||
494 | return ProcessingFailed ? 1 : (FileSkipped ? 2 : 0); | |||
495 | } | |||
496 | ||||
497 | namespace { | |||
498 | ||||
499 | class ASTBuilderAction : public ToolAction { | |||
500 | std::vector<std::unique_ptr<ASTUnit>> &ASTs; | |||
501 | ||||
502 | public: | |||
503 | ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {} | |||
504 | ||||
505 | bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, | |||
506 | FileManager *Files, | |||
507 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
508 | DiagnosticConsumer *DiagConsumer) override { | |||
509 | std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( | |||
510 | Invocation, std::move(PCHContainerOps), | |||
511 | CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(), | |||
512 | DiagConsumer, | |||
513 | /*ShouldOwnClient=*/false), | |||
514 | Files); | |||
515 | if (!AST) | |||
516 | return false; | |||
517 | ||||
518 | ASTs.push_back(std::move(AST)); | |||
519 | return true; | |||
520 | } | |||
521 | }; | |||
522 | ||||
523 | } // namespace | |||
524 | ||||
525 | int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) { | |||
526 | ASTBuilderAction Action(ASTs); | |||
527 | return run(&Action); | |||
528 | } | |||
529 | ||||
530 | namespace clang { | |||
531 | namespace tooling { | |||
532 | ||||
533 | std::unique_ptr<ASTUnit> | |||
534 | buildASTFromCode(const Twine &Code, const Twine &FileName, | |||
535 | std::shared_ptr<PCHContainerOperations> PCHContainerOps) { | |||
536 | return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName, | |||
| ||||
537 | "clang-tool", std::move(PCHContainerOps)); | |||
538 | } | |||
539 | ||||
540 | std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( | |||
541 | const Twine &Code, const std::vector<std::string> &Args, | |||
542 | const Twine &FileName, const Twine &ToolName, | |||
543 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
544 | ArgumentsAdjuster Adjuster) { | |||
545 | SmallString<16> FileNameStorage; | |||
546 | StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); | |||
547 | ||||
548 | std::vector<std::unique_ptr<ASTUnit>> ASTs; | |||
549 | ASTBuilderAction Action(ASTs); | |||
550 | llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( | |||
551 | new vfs::OverlayFileSystem(vfs::getRealFileSystem())); | |||
552 | llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( | |||
553 | new vfs::InMemoryFileSystem); | |||
554 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); | |||
555 | llvm::IntrusiveRefCntPtr<FileManager> Files( | |||
556 | new FileManager(FileSystemOptions(), OverlayFileSystem)); | |||
557 | ||||
558 | ToolInvocation Invocation( | |||
559 | getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), | |||
560 | &Action, Files.get(), std::move(PCHContainerOps)); | |||
561 | ||||
562 | SmallString<1024> CodeStorage; | |||
563 | InMemoryFileSystem->addFile(FileNameRef, 0, | |||
564 | llvm::MemoryBuffer::getMemBuffer( | |||
565 | Code.toNullTerminatedStringRef(CodeStorage))); | |||
566 | if (!Invocation.run()) | |||
567 | return nullptr; | |||
568 | ||||
569 | assert(ASTs.size() == 1)(static_cast <bool> (ASTs.size() == 1) ? void (0) : __assert_fail ("ASTs.size() == 1", "/build/llvm-toolchain-snapshot-7~svn329677/tools/clang/lib/Tooling/Tooling.cpp" , 569, __extension__ __PRETTY_FUNCTION__)); | |||
570 | return std::move(ASTs[0]); | |||
571 | } | |||
572 | ||||
573 | } // namespace tooling | |||
574 | } // namespace clang |
1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file defines the RefCountedBase, ThreadSafeRefCountedBase, and | |||
11 | // IntrusiveRefCntPtr classes. | |||
12 | // | |||
13 | // IntrusiveRefCntPtr is a smart pointer to an object which maintains a | |||
14 | // reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a | |||
15 | // refcount member variable and methods for updating the refcount. An object | |||
16 | // that inherits from (ThreadSafe)RefCountedBase deletes itself when its | |||
17 | // refcount hits zero. | |||
18 | // | |||
19 | // For example: | |||
20 | // | |||
21 | // class MyClass : public RefCountedBase<MyClass> {}; | |||
22 | // | |||
23 | // void foo() { | |||
24 | // // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by | |||
25 | // // 1 (from 0 in this case). | |||
26 | // IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); | |||
27 | // | |||
28 | // // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. | |||
29 | // IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); | |||
30 | // | |||
31 | // // Constructing an IntrusiveRefCntPtr has no effect on the object's | |||
32 | // // refcount. After a move, the moved-from pointer is null. | |||
33 | // IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); | |||
34 | // assert(Ptr1 == nullptr); | |||
35 | // | |||
36 | // // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. | |||
37 | // Ptr2.reset(); | |||
38 | // | |||
39 | // // The object deletes itself when we return from the function, because | |||
40 | // // Ptr3's destructor decrements its refcount to 0. | |||
41 | // } | |||
42 | // | |||
43 | // You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: | |||
44 | // | |||
45 | // IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); | |||
46 | // OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required | |||
47 | // | |||
48 | // IntrusiveRefCntPtr works with any class that | |||
49 | // | |||
50 | // - inherits from (ThreadSafe)RefCountedBase, | |||
51 | // - has Retain() and Release() methods, or | |||
52 | // - specializes IntrusiveRefCntPtrInfo. | |||
53 | // | |||
54 | //===----------------------------------------------------------------------===// | |||
55 | ||||
56 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
57 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
58 | ||||
59 | #include <atomic> | |||
60 | #include <cassert> | |||
61 | #include <cstddef> | |||
62 | ||||
63 | namespace llvm { | |||
64 | ||||
65 | /// A CRTP mixin class that adds reference counting to a type. | |||
66 | /// | |||
67 | /// The lifetime of an object which inherits from RefCountedBase is managed by | |||
68 | /// calls to Release() and Retain(), which increment and decrement the object's | |||
69 | /// refcount, respectively. When a Release() call decrements the refcount to 0, | |||
70 | /// the object deletes itself. | |||
71 | template <class Derived> class RefCountedBase { | |||
72 | mutable unsigned RefCount = 0; | |||
73 | ||||
74 | public: | |||
75 | RefCountedBase() = default; | |||
76 | RefCountedBase(const RefCountedBase &) {} | |||
77 | ||||
78 | void Retain() const { ++RefCount; } | |||
79 | ||||
80 | void Release() const { | |||
81 | assert(RefCount > 0 && "Reference count is already zero.")(static_cast <bool> (RefCount > 0 && "Reference count is already zero." ) ? void (0) : __assert_fail ("RefCount > 0 && \"Reference count is already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn329677/include/llvm/ADT/IntrusiveRefCntPtr.h" , 81, __extension__ __PRETTY_FUNCTION__)); | |||
82 | if (--RefCount == 0) | |||
83 | delete static_cast<const Derived *>(this); | |||
84 | } | |||
85 | }; | |||
86 | ||||
87 | /// A thread-safe version of \c RefCountedBase. | |||
88 | template <class Derived> class ThreadSafeRefCountedBase { | |||
89 | mutable std::atomic<int> RefCount; | |||
90 | ||||
91 | protected: | |||
92 | ThreadSafeRefCountedBase() : RefCount(0) {} | |||
93 | ||||
94 | public: | |||
95 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } | |||
96 | ||||
97 | void Release() const { | |||
98 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; | |||
99 | assert(NewRefCount >= 0 && "Reference count was already zero.")(static_cast <bool> (NewRefCount >= 0 && "Reference count was already zero." ) ? void (0) : __assert_fail ("NewRefCount >= 0 && \"Reference count was already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn329677/include/llvm/ADT/IntrusiveRefCntPtr.h" , 99, __extension__ __PRETTY_FUNCTION__)); | |||
100 | if (NewRefCount == 0) | |||
101 | delete static_cast<const Derived *>(this); | |||
102 | } | |||
103 | }; | |||
104 | ||||
105 | /// Class you can specialize to provide custom retain/release functionality for | |||
106 | /// a type. | |||
107 | /// | |||
108 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr | |||
109 | /// works with any type which defines Retain() and Release() functions -- you | |||
110 | /// can define those functions yourself if RefCountedBase doesn't work for you. | |||
111 | /// | |||
112 | /// One case when you might want to specialize this type is if you have | |||
113 | /// - Foo.h defines type Foo and includes Bar.h, and | |||
114 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. | |||
115 | /// | |||
116 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in | |||
117 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h | |||
118 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call | |||
119 | /// T::Retain and T::Release. | |||
120 | /// | |||
121 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which | |||
122 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then | |||
123 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any | |||
124 | /// functions on Foo itself, because Foo would be an incomplete type. | |||
125 | template <typename T> struct IntrusiveRefCntPtrInfo { | |||
126 | static void retain(T *obj) { obj->Retain(); } | |||
127 | static void release(T *obj) { obj->Release(); } | |||
128 | }; | |||
129 | ||||
130 | /// A smart pointer to a reference-counted object that inherits from | |||
131 | /// RefCountedBase or ThreadSafeRefCountedBase. | |||
132 | /// | |||
133 | /// This class increments its pointee's reference count when it is created, and | |||
134 | /// decrements its refcount when it's destroyed (or is changed to point to a | |||
135 | /// different object). | |||
136 | template <typename T> class IntrusiveRefCntPtr { | |||
137 | T *Obj = nullptr; | |||
138 | ||||
139 | public: | |||
140 | using element_type = T; | |||
141 | ||||
142 | explicit IntrusiveRefCntPtr() = default; | |||
143 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } | |||
144 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } | |||
145 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } | |||
146 | ||||
147 | template <class X> | |||
148 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { | |||
149 | S.Obj = nullptr; | |||
150 | } | |||
151 | ||||
152 | template <class X> | |||
153 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { | |||
154 | retain(); | |||
155 | } | |||
156 | ||||
157 | ~IntrusiveRefCntPtr() { release(); } | |||
| ||||
158 | ||||
159 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { | |||
160 | swap(S); | |||
161 | return *this; | |||
162 | } | |||
163 | ||||
164 | T &operator*() const { return *Obj; } | |||
165 | T *operator->() const { return Obj; } | |||
166 | T *get() const { return Obj; } | |||
167 | explicit operator bool() const { return Obj; } | |||
168 | ||||
169 | void swap(IntrusiveRefCntPtr &other) { | |||
170 | T *tmp = other.Obj; | |||
171 | other.Obj = Obj; | |||
172 | Obj = tmp; | |||
173 | } | |||
174 | ||||
175 | void reset() { | |||
176 | release(); | |||
177 | Obj = nullptr; | |||
178 | } | |||
179 | ||||
180 | void resetWithoutRelease() { Obj = nullptr; } | |||
181 | ||||
182 | private: | |||
183 | void retain() { | |||
184 | if (Obj) | |||
185 | IntrusiveRefCntPtrInfo<T>::retain(Obj); | |||
186 | } | |||
187 | ||||
188 | void release() { | |||
189 | if (Obj) | |||
190 | IntrusiveRefCntPtrInfo<T>::release(Obj); | |||
191 | } | |||
192 | ||||
193 | template <typename X> friend class IntrusiveRefCntPtr; | |||
194 | }; | |||
195 | ||||
196 | template <class T, class U> | |||
197 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, | |||
198 | const IntrusiveRefCntPtr<U> &B) { | |||
199 | return A.get() == B.get(); | |||
200 | } | |||
201 | ||||
202 | template <class T, class U> | |||
203 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, | |||
204 | const IntrusiveRefCntPtr<U> &B) { | |||
205 | return A.get() != B.get(); | |||
206 | } | |||
207 | ||||
208 | template <class T, class U> | |||
209 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
210 | return A.get() == B; | |||
211 | } | |||
212 | ||||
213 | template <class T, class U> | |||
214 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
215 | return A.get() != B; | |||
216 | } | |||
217 | ||||
218 | template <class T, class U> | |||
219 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
220 | return A == B.get(); | |||
221 | } | |||
222 | ||||
223 | template <class T, class U> | |||
224 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
225 | return A != B.get(); | |||
226 | } | |||
227 | ||||
228 | template <class T> | |||
229 | bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
230 | return !B; | |||
231 | } | |||
232 | ||||
233 | template <class T> | |||
234 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
235 | return B == A; | |||
236 | } | |||
237 | ||||
238 | template <class T> | |||
239 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
240 | return !(A == B); | |||
241 | } | |||
242 | ||||
243 | template <class T> | |||
244 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
245 | return !(A == B); | |||
246 | } | |||
247 | ||||
248 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from | |||
249 | // Casting.h. | |||
250 | template <typename From> struct simplify_type; | |||
251 | ||||
252 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { | |||
253 | using SimpleType = T *; | |||
254 | ||||
255 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { | |||
256 | return Val.get(); | |||
257 | } | |||
258 | }; | |||
259 | ||||
260 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { | |||
261 | using SimpleType = /*const*/ T *; | |||
262 | ||||
263 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { | |||
264 | return Val.get(); | |||
265 | } | |||
266 | }; | |||
267 | ||||
268 | } // end namespace llvm | |||
269 | ||||
270 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |