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"
17#include "clang/Frontend/CompilerInstance.h"
18#include "clang/Frontend/TextDiagnosticPrinter.h"
19#include "clang/Lex/Preprocessor.h"
20#include "clang/Parse/ParseAST.h"
21#include "clang/Serialization/ASTReader.h"
22#include "clang/Serialization/ASTWriter.h"
23#include "llvm/Support/MemoryBuffer.h"
24
25using namespace clang;
26
27namespace {
28class ChainedIncludesSource : public ExternalSemaSource {
29public:
30  ~ChainedIncludesSource() override;
31
32  ExternalSemaSource &getFinalReader() const { return *FinalReader; }
33
34  std::vector<CompilerInstance *> CIs;
35  IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
36
37protected:
38  //===----------------------------------------------------------------------===//
39  // ExternalASTSource interface.
40  //===----------------------------------------------------------------------===//
41
42  Decl *GetExternalDecl(uint32_t ID) override;
43  Selector GetExternalSelector(uint32_t ID) override;
44  uint32_t GetNumExternalSelectors() override;
45  Stmt *GetExternalDeclStmt(uint64_t Offset) override;
46  CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
47  CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
48  bool FindExternalVisibleDeclsByName(const DeclContext *DC,
49                                      DeclarationName Name) override;
50  ExternalLoadResult
51  FindExternalLexicalDecls(const DeclContext *DC,
52                           bool (*isKindWeWant)(Decl::Kind),
53                           SmallVectorImpl<Decl *> &Result) override;
54  void CompleteType(TagDecl *Tag) override;
55  void CompleteType(ObjCInterfaceDecl *Class) override;
56  void StartedDeserializing() override;
57  void FinishedDeserializing() override;
58  void StartTranslationUnit(ASTConsumer *Consumer) override;
59  void PrintStats() override;
60
61  /// Return the amount of memory used by memory buffers, breaking down
62  /// by heap-backed versus mmap'ed memory.
63  void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override;
64
65  //===----------------------------------------------------------------------===//
66  // ExternalSemaSource interface.
67  //===----------------------------------------------------------------------===//
68
69  void InitializeSema(Sema &S) override;
70  void ForgetSema() override;
71  void ReadMethodPool(Selector Sel) override;
72  bool LookupUnqualified(LookupResult &R, Scope *S) override;
73};
74}
75
76static ASTReader *
77createASTReader(CompilerInstance &CI, StringRef pchFile,
78                SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
79                SmallVectorImpl<std::string> &bufNames,
80                ASTDeserializationListener *deserialListener = nullptr) {
81  Preprocessor &PP = CI.getPreprocessor();
82  std::unique_ptr<ASTReader> Reader;
83  Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
84                             /*DisableValidation=*/true));
85  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
86    StringRef sr(bufNames[ti]);
87    Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
88  }
89  Reader->setDeserializationListener(deserialListener);
90  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
91                          ASTReader::ARR_None)) {
92  case ASTReader::Success:
93    // Set the predefines buffer as suggested by the PCH reader.
94    PP.setPredefines(Reader->getSuggestedPredefines());
95    return Reader.release();
96
97  case ASTReader::Failure:
98  case ASTReader::Missing:
99  case ASTReader::OutOfDate:
100  case ASTReader::VersionMismatch:
101  case ASTReader::ConfigurationMismatch:
102  case ASTReader::HadErrors:
103    break;
104  }
105  return nullptr;
106}
107
108ChainedIncludesSource::~ChainedIncludesSource() {
109  for (unsigned i = 0, e = CIs.size(); i != e; ++i)
110    delete CIs[i];
111}
112
113IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
114    CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
115
116  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
117  assert(!includes.empty() && "No '-chain-include' in options!");
118
119  IntrusiveRefCntPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
120  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
121
122  SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
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());
144    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
145    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
146        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
147
148    std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
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    SmallVector<char, 256> serialAST;
161    llvm::raw_svector_ostream OS(serialAST);
162    auto consumer =
163        llvm::make_unique<PCHGenerator>(Clang->getPreprocessor(), "-", nullptr,
164                                        /*isysroot=*/"", &OS);
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();
172      PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
173                                             PP.getLangOpts());
174    } else {
175      assert(!SerialBufs.empty());
176      SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
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
186      IntrusiveRefCntPtr<ASTReader> Reader;
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    SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(OS.str()));
202    source->CIs.push_back(Clang.release());
203  }
204
205  assert(!SerialBufs.empty());
206  std::string pchName = includes.back() + ".pch-final";
207  serialBufNames.push_back(pchName);
208  Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
209  if (!Reader)
210    return nullptr;
211
212  source->FinalReader = Reader;
213  return source;
214}
215
216//===----------------------------------------------------------------------===//
217// ExternalASTSource interface.
218//===----------------------------------------------------------------------===//
219
220Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
221  return getFinalReader().GetExternalDecl(ID);
222}
223Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
224  return getFinalReader().GetExternalSelector(ID);
225}
226uint32_t ChainedIncludesSource::GetNumExternalSelectors() {
227  return getFinalReader().GetNumExternalSelectors();
228}
229Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
230  return getFinalReader().GetExternalDeclStmt(Offset);
231}
232CXXBaseSpecifier *
233ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
234  return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
235}
236CXXCtorInitializer **
237ChainedIncludesSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
238  return getFinalReader().GetExternalCXXCtorInitializers(Offset);
239}
240bool
241ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
242                                                      DeclarationName Name) {
243  return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
244}
245ExternalLoadResult
246ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
247                                      bool (*isKindWeWant)(Decl::Kind),
248                                      SmallVectorImpl<Decl*> &Result) {
249  return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
250}
251void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
252  return getFinalReader().CompleteType(Tag);
253}
254void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
255  return getFinalReader().CompleteType(Class);
256}
257void ChainedIncludesSource::StartedDeserializing() {
258  return getFinalReader().StartedDeserializing();
259}
260void ChainedIncludesSource::FinishedDeserializing() {
261  return getFinalReader().FinishedDeserializing();
262}
263void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
264  return getFinalReader().StartTranslationUnit(Consumer);
265}
266void ChainedIncludesSource::PrintStats() {
267  return getFinalReader().PrintStats();
268}
269void ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{
270  for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
271    if (const ExternalASTSource *eSrc =
272        CIs[i]->getASTContext().getExternalSource()) {
273      eSrc->getMemoryBufferSizes(sizes);
274    }
275  }
276
277  getFinalReader().getMemoryBufferSizes(sizes);
278}
279
280void ChainedIncludesSource::InitializeSema(Sema &S) {
281  return getFinalReader().InitializeSema(S);
282}
283void ChainedIncludesSource::ForgetSema() {
284  return getFinalReader().ForgetSema();
285}
286void ChainedIncludesSource::ReadMethodPool(Selector Sel) {
287  getFinalReader().ReadMethodPool(Sel);
288}
289bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
290  return getFinalReader().LookupUnqualified(R, S);
291}
292
293