clang 20.0.0git
ChainedIncludesSource.cpp
Go to the documentation of this file.
1//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
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// This file defines the ChainedIncludesSource class, which converts headers
10// to chained PCHs in memory, mainly used for testing.
11//
12//===----------------------------------------------------------------------===//
13
25#include "llvm/Support/MemoryBuffer.h"
26
27using namespace clang;
28
29namespace {
30class ChainedIncludesSource : public ExternalSemaSource {
31public:
32 ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)
33 : CIs(std::move(CIs)) {}
34
35protected:
36 //===--------------------------------------------------------------------===//
37 // ExternalASTSource interface.
38 //===--------------------------------------------------------------------===//
39
40 /// Return the amount of memory used by memory buffers, breaking down
41 /// by heap-backed versus mmap'ed memory.
42 void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
43 for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
44 if (const ExternalASTSource *eSrc =
45 CIs[i]->getASTContext().getExternalSource()) {
46 eSrc->getMemoryBufferSizes(sizes);
47 }
48 }
49 }
50
51private:
52 std::vector<std::unique_ptr<CompilerInstance>> CIs;
53};
54} // end anonymous namespace
55
56static ASTReader *
57createASTReader(CompilerInstance &CI, StringRef pchFile,
58 SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
60 ASTDeserializationListener *deserialListener = nullptr) {
62 std::unique_ptr<ASTReader> Reader;
63 Reader.reset(new ASTReader(
65 /*Extensions=*/{},
66 /*isysroot=*/"", DisableValidationForModuleKind::PCH));
67 for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
68 StringRef sr(bufNames[ti]);
69 Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
70 }
71 Reader->setDeserializationListener(deserialListener);
72 switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
75 // Set the predefines buffer as suggested by the PCH reader.
76 PP.setPredefines(Reader->getSuggestedPredefines());
77 return Reader.release();
78
85 break;
86 }
87 return nullptr;
88}
89
92
93 std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
94 assert(!includes.empty() && "No '-chain-include' in options!");
95
96 std::vector<std::unique_ptr<CompilerInstance>> CIs;
97 InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
98
100 SmallVector<std::string, 4> serialBufNames;
101
102 for (unsigned i = 0, e = includes.size(); i != e; ++i) {
103 bool firstInclude = (i == 0);
104 std::unique_ptr<CompilerInvocation> CInvok;
105 CInvok.reset(new CompilerInvocation(CI.getInvocation()));
106
107 CInvok->getPreprocessorOpts().ChainedIncludes.clear();
108 CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
109 CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =
110 DisableValidationForModuleKind::PCH;
111 CInvok->getPreprocessorOpts().Includes.clear();
112 CInvok->getPreprocessorOpts().MacroIncludes.clear();
113 CInvok->getPreprocessorOpts().Macros.clear();
114
115 CInvok->getFrontendOpts().Inputs.clear();
116 FrontendInputFile InputFile(includes[i], IK);
117 CInvok->getFrontendOpts().Inputs.push_back(InputFile);
118
119 TextDiagnosticPrinter *DiagClient =
120 new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
123 new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
124
125 std::unique_ptr<CompilerInstance> Clang(
127 Clang->setInvocation(std::move(CInvok));
128 Clang->setDiagnostics(Diags.get());
129 Clang->setTarget(TargetInfo::CreateTargetInfo(
130 Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
131 Clang->createFileManager();
132 Clang->createSourceManager(Clang->getFileManager());
133 Clang->createPreprocessor(TU_Prefix);
134 Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
135 &Clang->getPreprocessor());
136 Clang->createASTContext();
137
138 auto Buffer = std::make_shared<PCHBuffer>();
140 auto consumer = std::make_unique<PCHGenerator>(
141 Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
142 Buffer, Extensions, /*AllowASTWithErrors=*/true);
143 Clang->getASTContext().setASTMutationListener(
144 consumer->GetASTMutationListener());
145 Clang->setASTConsumer(std::move(consumer));
146 Clang->createSema(TU_Prefix, nullptr);
147
148 if (firstInclude) {
149 Preprocessor &PP = Clang->getPreprocessor();
151 PP.getLangOpts());
152 } else {
153 assert(!SerialBufs.empty());
155 // TODO: Pass through the existing MemoryBuffer instances instead of
156 // allocating new ones.
157 for (auto &SB : SerialBufs)
158 Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
159 std::string pchName = includes[i-1];
160 llvm::raw_string_ostream os(pchName);
161 os << ".pch" << i-1;
162 serialBufNames.push_back(os.str());
163
165 Reader = createASTReader(
166 *Clang, pchName, Bufs, serialBufNames,
167 Clang->getASTConsumer().GetASTDeserializationListener());
168 if (!Reader)
169 return nullptr;
170 Clang->setASTReader(Reader);
171 Clang->getASTContext().setExternalSource(Reader);
172 }
173
174 if (!Clang->InitializeSourceManager(InputFile))
175 return nullptr;
176
177 ParseAST(Clang->getSema());
178 Clang->getDiagnosticClient().EndSourceFile();
179 assert(Buffer->IsComplete && "serialization did not complete");
180 auto &serialAST = Buffer->Data;
181 SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
182 StringRef(serialAST.data(), serialAST.size())));
183 serialAST.clear();
184 CIs.push_back(std::move(Clang));
185 }
186
187 assert(!SerialBufs.empty());
188 std::string pchName = includes.back() + ".pch-final";
189 serialBufNames.push_back(pchName);
190 Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
191 if (!Reader)
192 return nullptr;
193
194 auto ChainedSrc =
195 llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs));
196 return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(
197 ChainedSrc.get(), Reader.get());
198}
Defines enum values for all the target-independent builtin functions.
static ASTReader * createASTReader(CompilerInstance &CI, StringRef pchFile, SmallVectorImpl< std::unique_ptr< llvm::MemoryBuffer > > &MemBufs, SmallVectorImpl< std::string > &bufNames, ASTDeserializationListener *deserialListener=nullptr)
Defines the clang::Preprocessor interface.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:378
@ ARR_None
The client can't handle any AST loading failures.
Definition: ASTReader.h:1633
@ Success
The control block was read successfully.
Definition: ASTReader.h:401
@ ConfigurationMismatch
The AST file was written with a different language/target configuration.
Definition: ASTReader.h:418
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition: ASTReader.h:411
@ Failure
The AST file itself appears corrupted.
Definition: ASTReader.h:404
@ VersionMismatch
The AST file was written by a different version of Clang.
Definition: ASTReader.h:414
@ HadErrors
The AST file has errors.
Definition: ASTReader.h:421
@ Missing
The AST file was missing.
Definition: ASTReader.h:407
void initializeBuiltins(IdentifierTable &Table, const LangOptions &LangOpts)
Mark the identifiers for all the builtins with their appropriate builtin ID # and mark any non-portab...
Definition: Builtins.cpp:134
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
InMemoryModuleCache & getModuleCache() const
Preprocessor & getPreprocessor() const
Return the current preprocessor.
ASTContext & getASTContext() const
FrontendOptions & getFrontendOpts()
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
Helper class for holding the data necessary to invoke the compiler.
Used for handling and querying diagnostic IDs.
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
Abstract interface for external sources of AST nodes.
MemoryBufferSizes getMemoryBufferSizes() const
Return the amount of memory used by memory buffers, breaking down by heap-backed versus mmap'ed memor...
An abstract interface that should be implemented by external AST sources that also provide informatio...
An input file for the front end.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
The kind of a file that we've been handed as an input.
std::vector< std::string > ChainedIncludes
Headers that will be converted to chained PCHs in memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:137
void setPredefines(std::string P)
Set the predefines for this Preprocessor.
IdentifierTable & getIdentifierTable()
Builtin::Context & getBuiltinInfo()
const LangOptions & getLangOpts() const
Encodes a location in the source.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:752
Defines the clang::TargetInfo interface.
@ MK_PCH
File is a PCH file treated as such.
Definition: ModuleFile.h:50
The JSON file list parser is used to communicate input to InstallAPI.
void ParseAST(Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, bool PrintStats=false, TranslationUnitKind TUKind=TU_Complete, CodeCompleteConsumer *CompletionConsumer=nullptr, bool SkipFunctionBodies=false)
Parse the entire file specified, notifying the ASTConsumer as the file is parsed.
Definition: ParseAST.cpp:100
IntrusiveRefCntPtr< ExternalSemaSource > createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr< ExternalSemaSource > &Reader)
The ChainedIncludesSource class converts headers to chained PCHs in memory, mainly for testing.
@ TU_Prefix
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:1071