clang  3.9.0
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"
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.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().ImplicitPTHInclude.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(CInvok.release());
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(), "-", nullptr, /*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 }
ASTContext & getASTContext() const
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...
DiagnosticOptions & getDiagnosticOpts()
The translation unit is a prefix to a translation unit, and is not complete.
Definition: LangOptions.h:177
std::unique_ptr< llvm::MemoryBuffer > Buffer
static ASTReader * createASTReader(CompilerInstance &CI, StringRef pchFile, SmallVectorImpl< std::unique_ptr< llvm::MemoryBuffer >> &MemBufs, SmallVectorImpl< std::string > &bufNames, ASTDeserializationListener *deserialListener=nullptr)
The AST file has errors.
Definition: ASTReader.h:343
Builtin::Context & getBuiltinInfo()
Definition: Preprocessor.h:700
void setPredefines(const char *P)
Set the predefines for this Preprocessor.
Definition: Preprocessor.h:929
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:690
FrontendOptions & getFrontendOpts()
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:135
The AST file itself appears corrupted.
Definition: ASTReader.h:331
Preprocessor & getPreprocessor() const
Return the current preprocessor.
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:8554
An input file for the front end.
The client can't handle any AST loading failures.
Definition: ASTReader.h:1360
The AST file was missing.
Definition: ASTReader.h:333
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:329
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Encodes a location in the source.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
File is a PCH file treated as such.
Options for controlling the compiler diagnostics engine.
std::vector< FrontendInputFile > Inputs
The input files and their types.
IdentifierTable & getIdentifierTable()
Definition: Preprocessor.h:697
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:81
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
The AST file was writtten with a different language/target configuration.
Definition: ASTReader.h:341
Reads an AST files chain containing the contents of a translation unit.
Definition: ASTReader.h:312
Used for handling and querying diagnostic IDs.
Helper class for holding the data necessary to invoke the compiler.
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:336
The AST file was written by a different version of Clang.
Definition: ASTReader.h:338
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:97