clang  9.0.0svn
ChainedIncludesSource.cpp
Go to the documentation of this file.
1 //===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the ChainedIncludesSource class, which converts headers
11 // to chained PCHs in memory, mainly used for testing.
12 //
13 //===----------------------------------------------------------------------===//
14 
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 ChainedIncludesSourceImpl : public ExternalSemaSource {
31 public:
32  ChainedIncludesSourceImpl(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 
55 /// Members of ChainedIncludesSource, factored out so we can initialize
56 /// them before we initialize the ExternalSemaSource base class.
57 struct ChainedIncludesSourceMembers {
58  ChainedIncludesSourceMembers(
59  std::vector<std::unique_ptr<CompilerInstance>> CIs,
60  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
61  : Impl(std::move(CIs)), FinalReader(std::move(FinalReader)) {}
62  ChainedIncludesSourceImpl Impl;
63  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
64 };
65 
66 /// Use MultiplexExternalSemaSource to dispatch all ExternalSemaSource
67 /// calls to the final reader.
68 class ChainedIncludesSource
69  : private ChainedIncludesSourceMembers,
71 public:
72  ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,
73  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
74  : ChainedIncludesSourceMembers(std::move(CIs), std::move(FinalReader)),
75  MultiplexExternalSemaSource(Impl, *this->FinalReader) {}
76 };
77 }
78 
79 static ASTReader *
80 createASTReader(CompilerInstance &CI, StringRef pchFile,
81  SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
83  ASTDeserializationListener *deserialListener = nullptr) {
84  Preprocessor &PP = CI.getPreprocessor();
85  std::unique_ptr<ASTReader> Reader;
86  Reader.reset(new ASTReader(PP, &CI.getASTContext(),
88  /*Extensions=*/{ },
89  /*isysroot=*/"", /*DisableValidation=*/true));
90  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
91  StringRef sr(bufNames[ti]);
92  Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
93  }
94  Reader->setDeserializationListener(deserialListener);
95  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
97  case ASTReader::Success:
98  // Set the predefines buffer as suggested by the PCH reader.
99  PP.setPredefines(Reader->getSuggestedPredefines());
100  return Reader.release();
101 
102  case ASTReader::Failure:
103  case ASTReader::Missing:
108  break;
109  }
110  return nullptr;
111 }
112 
115 
116  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
117  assert(!includes.empty() && "No '-chain-include' in options!");
118 
119  std::vector<std::unique_ptr<CompilerInstance>> CIs;
120  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
121 
123  SmallVector<std::string, 4> serialBufNames;
124 
125  for (unsigned i = 0, e = includes.size(); i != e; ++i) {
126  bool firstInclude = (i == 0);
127  std::unique_ptr<CompilerInvocation> CInvok;
128  CInvok.reset(new CompilerInvocation(CI.getInvocation()));
129 
130  CInvok->getPreprocessorOpts().ChainedIncludes.clear();
131  CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
132  CInvok->getPreprocessorOpts().DisablePCHValidation = true;
133  CInvok->getPreprocessorOpts().Includes.clear();
134  CInvok->getPreprocessorOpts().MacroIncludes.clear();
135  CInvok->getPreprocessorOpts().Macros.clear();
136 
137  CInvok->getFrontendOpts().Inputs.clear();
138  FrontendInputFile InputFile(includes[i], IK);
139  CInvok->getFrontendOpts().Inputs.push_back(InputFile);
140 
141  TextDiagnosticPrinter *DiagClient =
142  new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
145  new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
146 
147  std::unique_ptr<CompilerInstance> Clang(
149  Clang->setInvocation(std::move(CInvok));
150  Clang->setDiagnostics(Diags.get());
151  Clang->setTarget(TargetInfo::CreateTargetInfo(
152  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
153  Clang->createFileManager();
154  Clang->createSourceManager(Clang->getFileManager());
155  Clang->createPreprocessor(TU_Prefix);
156  Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
157  &Clang->getPreprocessor());
158  Clang->createASTContext();
159 
160  auto Buffer = std::make_shared<PCHBuffer>();
162  auto consumer = llvm::make_unique<PCHGenerator>(
163  Clang->getPreprocessor(), "-", /*isysroot=*/"", Buffer,
164  Extensions, /*AllowASTWithErrors=*/true);
165  Clang->getASTContext().setASTMutationListener(
166  consumer->GetASTMutationListener());
167  Clang->setASTConsumer(std::move(consumer));
168  Clang->createSema(TU_Prefix, nullptr);
169 
170  if (firstInclude) {
171  Preprocessor &PP = Clang->getPreprocessor();
173  PP.getLangOpts());
174  } else {
175  assert(!SerialBufs.empty());
177  // TODO: Pass through the existing MemoryBuffer instances instead of
178  // allocating new ones.
179  for (auto &SB : SerialBufs)
180  Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
181  std::string pchName = includes[i-1];
182  llvm::raw_string_ostream os(pchName);
183  os << ".pch" << i-1;
184  serialBufNames.push_back(os.str());
185 
187  Reader = createASTReader(
188  *Clang, pchName, Bufs, serialBufNames,
189  Clang->getASTConsumer().GetASTDeserializationListener());
190  if (!Reader)
191  return nullptr;
192  Clang->setModuleManager(Reader);
193  Clang->getASTContext().setExternalSource(Reader);
194  }
195 
196  if (!Clang->InitializeSourceManager(InputFile))
197  return nullptr;
198 
199  ParseAST(Clang->getSema());
200  Clang->getDiagnosticClient().EndSourceFile();
201  assert(Buffer->IsComplete && "serialization did not complete");
202  auto &serialAST = Buffer->Data;
203  SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
204  StringRef(serialAST.data(), serialAST.size())));
205  serialAST.clear();
206  CIs.push_back(std::move(Clang));
207  }
208 
209  assert(!SerialBufs.empty());
210  std::string pchName = includes.back() + ".pch-final";
211  serialBufNames.push_back(pchName);
212  Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
213  if (!Reader)
214  return nullptr;
215 
217  new ChainedIncludesSource(std::move(CIs), Reader));
218 }
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:368
static ASTReader * createASTReader(CompilerInstance &CI, StringRef pchFile, SmallVectorImpl< std::unique_ptr< llvm::MemoryBuffer >> &MemBufs, SmallVectorImpl< std::string > &bufNames, ASTDeserializationListener *deserialListener=nullptr)
ASTContext & getASTContext() const
The AST file has errors.
Definition: ASTReader.h:404
Builtin::Context & getBuiltinInfo()
Definition: Preprocessor.h:826
void setPredefines(const char *P)
Set the predefines for this Preprocessor.
Definition: Format.h:2072
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:815
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:387
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:600
An input file for the front end.
The client can&#39;t handle any AST loading failures.
Definition: ASTReader.h:1508
The AST file was missing.
Definition: ASTReader.h:390
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:384
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:51
Options for controlling the compiler diagnostics engine.
std::vector< FrontendInputFile > Inputs
The input files and their types.
IdentifierTable & getIdentifierTable()
Definition: Preprocessor.h:823
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:87
The AST file was writtten with a different language/target configuration.
Definition: ASTReader.h:401
Dataflow Directional Tag Classes.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:355
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:394
The AST file was written by a different version of Clang.
Definition: ASTReader.h:397
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:125