clang  19.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 
14 #include "clang/Basic/Builtins.h"
15 #include "clang/Basic/TargetInfo.h"
16 #include "clang/Frontend/ASTUnit.h"
19 #include "clang/Lex/Preprocessor.h"
21 #include "clang/Parse/ParseAST.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 
27 using namespace clang;
28 
29 namespace {
30 class ChainedIncludesSource : public ExternalSemaSource {
31 public:
32  ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)
33  : CIs(std::move(CIs)) {}
34 
35 protected:
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 
51 private:
52  std::vector<std::unique_ptr<CompilerInstance>> CIs;
53 };
54 } // end anonymous namespace
55 
56 static ASTReader *
57 createASTReader(CompilerInstance &CI, StringRef pchFile,
58  SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
60  ASTDeserializationListener *deserialListener = nullptr) {
61  Preprocessor &PP = CI.getPreprocessor();
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(),
74  case ASTReader::Success:
75  // Set the predefines buffer as suggested by the PCH reader.
76  PP.setPredefines(Reader->getSuggestedPredefines());
77  return Reader.release();
78 
79  case ASTReader::Failure:
80  case ASTReader::Missing:
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 =
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:366
@ ARR_None
The client can't handle any AST loading failures.
Definition: ASTReader.h:1611
@ Success
The control block was read successfully.
Definition: ASTReader.h:387
@ ConfigurationMismatch
The AST file was written with a different language/target configuration.
Definition: ASTReader.h:404
@ OutOfDate
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition: ASTReader.h:397
@ Failure
The AST file itself appears corrupted.
Definition: ASTReader.h:390
@ VersionMismatch
The AST file was written by a different version of Clang.
Definition: ASTReader.h:400
@ HadErrors
The AST file has errors.
Definition: ASTReader.h:407
@ Missing
The AST file was missing.
Definition: ASTReader.h:393
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:128
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
CompilerInvocation & getInvocation()
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
PreprocessorOptions & getPreprocessorOpts()
InMemoryModuleCache & getModuleCache() const
ASTContext & getASTContext() const
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
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:193
Abstract interface for external sources of AST nodes.
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:128
IdentifierTable & getIdentifierTable()
void setPredefines(std::string P)
Set the predefines for this Preprocessor.
const LangOptions & getLangOpts() const
Builtin::Context & getBuiltinInfo()
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:815
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:101
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:1080
@ PCH
Disable validation for a precompiled header and the modules it depends on.
Definition: Format.h:5433