1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Utility for creating an ASTUnit from a vector of command line arguments.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/CreateASTUnitFromArgs.h"
#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Serialization/ModuleCache.h"
#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
/// Create an ASTUnit from a vector of command line arguments, which must
/// specify exactly one source file.
///
/// \param ArgBegin - The beginning of the argument vector.
///
/// \param ArgEnd - The end of the argument vector.
///
/// \param PCHContainerOps - The PCHContainerOperations to use for loading and
/// creating modules.
///
/// \param Diags - The diagnostics engine to use for reporting errors; its
/// lifetime is expected to extend past that of the returned ASTUnit.
///
/// \param ResourceFilesPath - The path to the compiler resource files.
///
/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false,
/// PCH are stored in temporary files.
///
/// \param PreambleStoragePath - The path to a directory, in which to create
/// temporary PCH files. If empty, the default system temporary directory is
/// used. This parameter is ignored if \p StorePreamblesInMemory is true.
///
/// \param ModuleFormat - If provided, uses the specific module format.
///
/// \param ErrAST - If non-null and parsing failed without any AST to return
/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
/// mainly to allow the caller to see the diagnostics.
///
/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses.
/// Note that preamble is saved to a temporary directory on a RealFileSystem,
/// so in order for it to be loaded correctly, VFS should have access to
/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used
/// if \p VFS is nullptr.
///
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
std::unique_ptr<ASTUnit> clang::CreateASTUnitFromCommandLine(
const char **ArgBegin, const char **ArgEnd,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
std::shared_ptr<DiagnosticOptions> DiagOpts,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
bool StorePreamblesInMemory, StringRef PreambleStoragePath,
bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
ArrayRef<ASTUnit::RemappedFile> RemappedFiles,
bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses,
TranslationUnitKind TUKind, bool CacheCodeCompletionResults,
bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors,
SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse,
bool UserFilesAreVolatile, bool ForSerialization,
bool RetainExcludedConditionalBlocks, std::optional<StringRef> ModuleFormat,
std::unique_ptr<ASTUnit> *ErrAST,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
// If no VFS was provided, create one that tracks the physical file system.
// If '-working-directory' was passed as an argument, 'createInvocation' will
// set this as the current working directory of the VFS.
if (!VFS)
VFS = llvm::vfs::createPhysicalFileSystem();
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
std::shared_ptr<CompilerInvocation> CI;
{
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
&StoredDiagnostics, nullptr);
CreateInvocationOptions CIOpts;
CIOpts.VFS = VFS;
CIOpts.Diags = Diags;
CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts));
if (!CI)
return nullptr;
}
// Override any files that need remapping
for (const auto &RemappedFile : RemappedFiles) {
CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
RemappedFile.second);
}
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
PPOpts.SingleFileParseMode = SingleFileParse;
PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath);
CI->getFrontendOpts().SkipFunctionBodies =
SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile;
if (ModuleFormat)
CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat);
// Create the AST unit.
std::unique_ptr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->DiagOpts = DiagOpts;
AST->Diagnostics = Diags;
AST->FileSystemOpts = CI->getFileSystemOpts();
AST->CodeGenOpts = std::make_unique<CodeGenOptions>(CI->getCodeGenOpts());
VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
AST->FileMgr =
llvm::makeIntrusiveRefCnt<FileManager>(AST->FileSystemOpts, VFS);
AST->StorePreamblesInMemory = StorePreamblesInMemory;
AST->PreambleStoragePath = PreambleStoragePath;
AST->ModCache = createCrossProcessModuleCache();
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->IncludeBriefCommentsInCodeCompletion =
IncludeBriefCommentsInCodeCompletion;
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->Invocation = CI;
AST->SkipFunctionBodies = SkipFunctionBodies;
if (ForSerialization)
AST->WriterData.reset(
new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts));
// Zero out now to ease cleanup during crash recovery.
CI = nullptr;
Diags = nullptr;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
PrecompilePreambleAfterNParses, VFS)) {
// Some error occurred, if caller wants to examine diagnostics, pass it the
// ASTUnit.
if (ErrAST) {
AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
ErrAST->swap(AST);
}
return nullptr;
}
return AST;
}
|