clang  10.0.0svn
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/TargetInfo.h"
15 #include "clang/Frontend/ASTUnit.h"
18 #include "clang/Lex/Preprocessor.h"
20 #include "clang/Parse/ParseAST.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 
26 using namespace clang;
27 
28 namespace {
29 class ChainedIncludesSourceImpl : public ExternalSemaSource {
30 public:
31  ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)
32  : CIs(std::move(CIs)) {}
33 
34 protected:
35  //===----------------------------------------------------------------------===//
36  // ExternalASTSource interface.
37  //===----------------------------------------------------------------------===//
38 
39  /// Return the amount of memory used by memory buffers, breaking down
40  /// by heap-backed versus mmap'ed memory.
41  void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
42  for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
43  if (const ExternalASTSource *eSrc =
44  CIs[i]->getASTContext().getExternalSource()) {
45  eSrc->getMemoryBufferSizes(sizes);
46  }
47  }
48  }
49 
50 private:
51  std::vector<std::unique_ptr<CompilerInstance>> CIs;
52 };
53 
54 /// Members of ChainedIncludesSource, factored out so we can initialize
55 /// them before we initialize the ExternalSemaSource base class.
56 struct ChainedIncludesSourceMembers {
57  ChainedIncludesSourceMembers(
58  std::vector<std::unique_ptr<CompilerInstance>> CIs,
59  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
60  : Impl(std::move(CIs)), FinalReader(std::move(FinalReader)) {}
61  ChainedIncludesSourceImpl Impl;
62  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
63 };
64 
65 /// Use MultiplexExternalSemaSource to dispatch all ExternalSemaSource
66 /// calls to the final reader.
67 class ChainedIncludesSource
68  : private ChainedIncludesSourceMembers,
70 public:
71  ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,
72  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
73  : ChainedIncludesSourceMembers(std::move(CIs), std::move(FinalReader)),
74  MultiplexExternalSemaSource(Impl, *this->FinalReader) {}
75 };
76 }
77 
78 static ASTReader *
79 createASTReader(CompilerInstance &CI, StringRef pchFile,
80  SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
82  ASTDeserializationListener *deserialListener = nullptr) {
83  Preprocessor &PP = CI.getPreprocessor();
84  std::unique_ptr<ASTReader> Reader;
85  Reader.reset(new ASTReader(PP, CI.getModuleCache(), &CI.getASTContext(),
87  /*Extensions=*/{},
88  /*isysroot=*/"", /*DisableValidation=*/true));
89  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
90  StringRef sr(bufNames[ti]);
91  Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
92  }
93  Reader->setDeserializationListener(deserialListener);
94  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
96  case ASTReader::Success:
97  // Set the predefines buffer as suggested by the PCH reader.
98  PP.setPredefines(Reader->getSuggestedPredefines());
99  return Reader.release();
100 
101  case ASTReader::Failure:
102  case ASTReader::Missing:
107  break;
108  }
109  return nullptr;
110 }
111 
114 
115  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
116  assert(!includes.empty() && "No '-chain-include' in options!");
117 
118  std::vector<std::unique_ptr<CompilerInstance>> CIs;
119  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
120 
122  SmallVector<std::string, 4> serialBufNames;
123 
124  for (unsigned i = 0, e = includes.size(); i != e; ++i) {
125  bool firstInclude = (i == 0);
126  std::unique_ptr<CompilerInvocation> CInvok;
127  CInvok.reset(new CompilerInvocation(CI.getInvocation()));
128 
129  CInvok->getPreprocessorOpts().ChainedIncludes.clear();
130  CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
131  CInvok->getPreprocessorOpts().DisablePCHValidation = true;
132  CInvok->getPreprocessorOpts().Includes.clear();
133  CInvok->getPreprocessorOpts().MacroIncludes.clear();
134  CInvok->getPreprocessorOpts().Macros.clear();
135 
136  CInvok->getFrontendOpts().Inputs.clear();
137  FrontendInputFile InputFile(includes[i], IK);
138  CInvok->getFrontendOpts().Inputs.push_back(InputFile);
139 
140  TextDiagnosticPrinter *DiagClient =
141  new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
144  new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
145 
146  std::unique_ptr<CompilerInstance> Clang(
148  Clang->setInvocation(std::move(CInvok));
149  Clang->setDiagnostics(Diags.get());
150  Clang->setTarget(TargetInfo::CreateTargetInfo(
151  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
152  Clang->createFileManager();
153  Clang->createSourceManager(Clang->getFileManager());
154  Clang->createPreprocessor(TU_Prefix);
155  Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
156  &Clang->getPreprocessor());
157  Clang->createASTContext();
158 
159  auto Buffer = std::make_shared<PCHBuffer>();
161  auto consumer = std::make_unique<PCHGenerator>(
162  Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
163  Buffer, Extensions, /*AllowASTWithErrors=*/true);
164  Clang->getASTContext().setASTMutationListener(
165  consumer->GetASTMutationListener());
166  Clang->setASTConsumer(std::move(consumer));
167  Clang->createSema(TU_Prefix, nullptr);
168 
169  if (firstInclude) {
170  Preprocessor &PP = Clang->getPreprocessor();
172  PP.getLangOpts());
173  } else {
174  assert(!SerialBufs.empty());
176  // TODO: Pass through the existing MemoryBuffer instances instead of
177  // allocating new ones.
178  for (auto &SB : SerialBufs)
179  Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
180  std::string pchName = includes[i-1];
181  llvm::raw_string_ostream os(pchName);
182  os << ".pch" << i-1;
183  serialBufNames.push_back(os.str());
184 
186  Reader = createASTReader(
187  *Clang, pchName, Bufs, serialBufNames,
188  Clang->getASTConsumer().GetASTDeserializationListener());
189  if (!Reader)
190  return nullptr;
191  Clang->setModuleManager(Reader);
192  Clang->getASTContext().setExternalSource(Reader);
193  }
194 
195  if (!Clang->InitializeSourceManager(InputFile))
196  return nullptr;
197 
198  ParseAST(Clang->getSema());
199  Clang->getDiagnosticClient().EndSourceFile();
200  assert(Buffer->IsComplete && "serialization did not complete");
201  auto &serialAST = Buffer->Data;
202  SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
203  StringRef(serialAST.data(), serialAST.size())));
204  serialAST.clear();
205  CIs.push_back(std::move(Clang));
206  }
207 
208  assert(!SerialBufs.empty());
209  std::string pchName = includes.back() + ".pch-final";
210  serialBufNames.push_back(pchName);
211  Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
212  if (!Reader)
213  return nullptr;
214 
216  new ChainedIncludesSource(std::move(CIs), Reader));
217 }
CompilerInvocation & getInvocation()
PreprocessorOptions & getPreprocessorOpts()
IntrusiveRefCntPtr< ExternalSemaSource > createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr< ExternalSemaSource > &Reader)
The ChainedIncludesSource class converts headers to chained PCHs in memory, mainly for testing...
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
DiagnosticOptions & getDiagnosticOpts()
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:384
static ASTReader * createASTReader(CompilerInstance &CI, StringRef pchFile, SmallVectorImpl< std::unique_ptr< llvm::MemoryBuffer >> &MemBufs, SmallVectorImpl< std::string > &bufNames, ASTDeserializationListener *deserialListener=nullptr)
InMemoryModuleCache & getModuleCache() const
ASTContext & getASTContext() const
The AST file has errors.
Definition: ASTReader.h:403
Builtin::Context & getBuiltinInfo()
Definition: Preprocessor.h:914
void setPredefines(const char *P)
Set the predefines for this Preprocessor.
Definition: Format.h:2392
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:904
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
The AST file itself appears corrupted.
Definition: ASTReader.h:386
std::vector< std::string > ChainedIncludes
Headers that will be converted to chained PCHs in memory.
An abstract interface that should be implemented by external AST sources that also provide informatio...
Defines the clang::Preprocessor interface.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:613
An input file for the front end.
The client can&#39;t handle any AST loading failures.
Definition: ASTReader.h:1513
The AST file was missing.
Definition: ASTReader.h:389
An abstract interface that should be implemented by external AST sources that also provide informatio...
Abstract interface for external sources of AST nodes.
The control block was read successfully.
Definition: ASTReader.h:383
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Encodes a location in the source.
File is a PCH file treated as such.
Definition: Module.h:50
Options for controlling the compiler diagnostics engine.
std::vector< FrontendInputFile > Inputs
The input files and their types.
IdentifierTable & getIdentifierTable()
Definition: Preprocessor.h:911
The kind of a file that we&#39;ve been handed as an input.
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:99
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:90
The AST file was writtten with a different language/target configuration.
Definition: ASTReader.h:400
Dataflow Directional Tag Classes.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:354
Used for handling and querying diagnostic IDs.
Helper class for holding the data necessary to invoke the compiler.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
Defines the clang::TargetInfo interface.
The AST file is out-of-date relative to its input files, and needs to be regenerated.
Definition: ASTReader.h:393
The AST file was written by a different version of Clang.
Definition: ASTReader.h:396
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:125