clang  6.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().ImplicitPTHInclude.clear();
133  CInvok->getPreprocessorOpts().DisablePCHValidation = true;
134  CInvok->getPreprocessorOpts().Includes.clear();
135  CInvok->getPreprocessorOpts().MacroIncludes.clear();
136  CInvok->getPreprocessorOpts().Macros.clear();
137 
138  CInvok->getFrontendOpts().Inputs.clear();
139  FrontendInputFile InputFile(includes[i], IK);
140  CInvok->getFrontendOpts().Inputs.push_back(InputFile);
141 
142  TextDiagnosticPrinter *DiagClient =
143  new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
146  new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
147 
148  std::unique_ptr<CompilerInstance> Clang(
150  Clang->setInvocation(std::move(CInvok));
151  Clang->setDiagnostics(Diags.get());
152  Clang->setTarget(TargetInfo::CreateTargetInfo(
153  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
154  Clang->createFileManager();
155  Clang->createSourceManager(Clang->getFileManager());
156  Clang->createPreprocessor(TU_Prefix);
157  Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
158  &Clang->getPreprocessor());
159  Clang->createASTContext();
160 
161  auto Buffer = std::make_shared<PCHBuffer>();
163  auto consumer = llvm::make_unique<PCHGenerator>(
164  Clang->getPreprocessor(), "-", /*isysroot=*/"", Buffer,
165  Extensions, /*AllowASTWithErrors=*/true);
166  Clang->getASTContext().setASTMutationListener(
167  consumer->GetASTMutationListener());
168  Clang->setASTConsumer(std::move(consumer));
169  Clang->createSema(TU_Prefix, nullptr);
170 
171  if (firstInclude) {
172  Preprocessor &PP = Clang->getPreprocessor();
174  PP.getLangOpts());
175  } else {
176  assert(!SerialBufs.empty());
178  // TODO: Pass through the existing MemoryBuffer instances instead of
179  // allocating new ones.
180  for (auto &SB : SerialBufs)
181  Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
182  std::string pchName = includes[i-1];
183  llvm::raw_string_ostream os(pchName);
184  os << ".pch" << i-1;
185  serialBufNames.push_back(os.str());
186 
188  Reader = createASTReader(
189  *Clang, pchName, Bufs, serialBufNames,
190  Clang->getASTConsumer().GetASTDeserializationListener());
191  if (!Reader)
192  return nullptr;
193  Clang->setModuleManager(Reader);
194  Clang->getASTContext().setExternalSource(Reader);
195  }
196 
197  if (!Clang->InitializeSourceManager(InputFile))
198  return nullptr;
199 
200  ParseAST(Clang->getSema());
201  Clang->getDiagnosticClient().EndSourceFile();
202  assert(Buffer->IsComplete && "serialization did not complete");
203  auto &serialAST = Buffer->Data;
204  SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
205  StringRef(serialAST.data(), serialAST.size())));
206  serialAST.clear();
207  CIs.push_back(std::move(Clang));
208  }
209 
210  assert(!SerialBufs.empty());
211  std::string pchName = includes.back() + ".pch-final";
212  serialBufNames.push_back(pchName);
213  Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
214  if (!Reader)
215  return nullptr;
216 
218  new ChainedIncludesSource(std::move(CIs), Reader));
219 }
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:247
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:407
Builtin::Context & getBuiltinInfo()
Definition: Preprocessor.h:822
void setPredefines(const char *P)
Set the predefines for this Preprocessor.
Definition: Format.h:1900
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:811
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:147
The AST file itself appears corrupted.
Definition: ASTReader.h:390
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:583
An input file for the front end.
The client can&#39;t handle any AST loading failures.
Definition: ASTReader.h:1486
The AST file was missing.
Definition: ASTReader.h:393
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:387
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:819
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:98
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:404
Dataflow Directional Tag Classes.
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:358
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:397
The AST file was written by a different version of Clang.
Definition: ASTReader.h:400
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:127