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