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  virtual ~ChainedIncludesSource();
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  CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
47  bool FindExternalVisibleDeclsByName(const DeclContext *DC,
48                                      DeclarationName Name) override;
49  ExternalLoadResult
50  FindExternalLexicalDecls(const DeclContext *DC,
51                           bool (*isKindWeWant)(Decl::Kind),
52                           SmallVectorImpl<Decl *> &Result) override;
53  void CompleteType(TagDecl *Tag) override;
54  void CompleteType(ObjCInterfaceDecl *Class) override;
55  void StartedDeserializing() override;
56  void FinishedDeserializing() override;
57  void StartTranslationUnit(ASTConsumer *Consumer) override;
58  void PrintStats() override;
59
60  /// Return the amount of memory used by memory buffers, breaking down
61  /// by heap-backed versus mmap'ed memory.
62  void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override;
63
64  //===----------------------------------------------------------------------===//
65  // ExternalSemaSource interface.
66  //===----------------------------------------------------------------------===//
67
68  void InitializeSema(Sema &S) override;
69  void ForgetSema() override;
70  void ReadMethodPool(Selector Sel) override;
71  bool LookupUnqualified(LookupResult &R, Scope *S) override;
72};
73}
74
75static ASTReader *
76createASTReader(CompilerInstance &CI, StringRef pchFile,
77                SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
78                SmallVectorImpl<std::string> &bufNames,
79                ASTDeserializationListener *deserialListener = nullptr) {
80  Preprocessor &PP = CI.getPreprocessor();
81  std::unique_ptr<ASTReader> Reader;
82  Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
83                             /*DisableValidation=*/true));
84  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
85    StringRef sr(bufNames[ti]);
86    Reader->addInMemoryBuffer(sr, memBufs[ti]);
87  }
88  Reader->setDeserializationListener(deserialListener);
89  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
90                          ASTReader::ARR_None)) {
91  case ASTReader::Success:
92    // Set the predefines buffer as suggested by the PCH reader.
93    PP.setPredefines(Reader->getSuggestedPredefines());
94    return Reader.release();
95
96  case ASTReader::Failure:
97  case ASTReader::Missing:
98  case ASTReader::OutOfDate:
99  case ASTReader::VersionMismatch:
100  case ASTReader::ConfigurationMismatch:
101  case ASTReader::HadErrors:
102    break;
103  }
104  return nullptr;
105}
106
107ChainedIncludesSource::~ChainedIncludesSource() {
108  for (unsigned i = 0, e = CIs.size(); i != e; ++i)
109    delete CIs[i];
110}
111
112IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
113    CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
114
115  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
116  assert(!includes.empty() && "No '-chain-include' in options!");
117
118  IntrusiveRefCntPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
119  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
120
121  SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
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());
143    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
144    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
145        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
146
147    std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
148    Clang->setInvocation(CInvok.release());
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    SmallVector<char, 256> serialAST;
160    llvm::raw_svector_ostream OS(serialAST);
161    std::unique_ptr<ASTConsumer> consumer;
162    consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", nullptr,
163                                    /*isysroot=*/"", &OS));
164    Clang->getASTContext().setASTMutationListener(
165                                            consumer->GetASTMutationListener());
166    Clang->setASTConsumer(consumer.release());
167    Clang->createSema(TU_Prefix, nullptr);
168
169    if (firstInclude) {
170      Preprocessor &PP = Clang->getPreprocessor();
171      PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
172                                             PP.getLangOpts());
173    } else {
174      assert(!serialBufs.empty());
175      SmallVector<llvm::MemoryBuffer *, 4> bufs;
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
185      IntrusiveRefCntPtr<ASTReader> Reader;
186      Reader = createASTReader(*Clang, pchName, bufs, serialBufNames,
187        Clang->getASTConsumer().GetASTDeserializationListener());
188      if (!Reader)
189        return nullptr;
190      Clang->setModuleManager(Reader);
191      Clang->getASTContext().setExternalSource(Reader);
192    }
193
194    if (!Clang->InitializeSourceManager(InputFile))
195      return nullptr;
196
197    ParseAST(Clang->getSema());
198    Clang->getDiagnosticClient().EndSourceFile();
199    serialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(OS.str()));
200    source->CIs.push_back(Clang.release());
201  }
202
203  assert(!serialBufs.empty());
204  std::string pchName = includes.back() + ".pch-final";
205  serialBufNames.push_back(pchName);
206  Reader = createASTReader(CI, pchName, serialBufs, serialBufNames);
207  if (!Reader)
208    return nullptr;
209
210  source->FinalReader = Reader;
211  return source;
212}
213
214//===----------------------------------------------------------------------===//
215// ExternalASTSource interface.
216//===----------------------------------------------------------------------===//
217
218Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
219  return getFinalReader().GetExternalDecl(ID);
220}
221Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
222  return getFinalReader().GetExternalSelector(ID);
223}
224uint32_t ChainedIncludesSource::GetNumExternalSelectors() {
225  return getFinalReader().GetNumExternalSelectors();
226}
227Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
228  return getFinalReader().GetExternalDeclStmt(Offset);
229}
230CXXBaseSpecifier *
231ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
232  return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
233}
234bool
235ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
236                                                      DeclarationName Name) {
237  return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
238}
239ExternalLoadResult
240ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
241                                      bool (*isKindWeWant)(Decl::Kind),
242                                      SmallVectorImpl<Decl*> &Result) {
243  return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
244}
245void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
246  return getFinalReader().CompleteType(Tag);
247}
248void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
249  return getFinalReader().CompleteType(Class);
250}
251void ChainedIncludesSource::StartedDeserializing() {
252  return getFinalReader().StartedDeserializing();
253}
254void ChainedIncludesSource::FinishedDeserializing() {
255  return getFinalReader().FinishedDeserializing();
256}
257void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
258  return getFinalReader().StartTranslationUnit(Consumer);
259}
260void ChainedIncludesSource::PrintStats() {
261  return getFinalReader().PrintStats();
262}
263void ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{
264  for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
265    if (const ExternalASTSource *eSrc =
266        CIs[i]->getASTContext().getExternalSource()) {
267      eSrc->getMemoryBufferSizes(sizes);
268    }
269  }
270
271  getFinalReader().getMemoryBufferSizes(sizes);
272}
273
274void ChainedIncludesSource::InitializeSema(Sema &S) {
275  return getFinalReader().InitializeSema(S);
276}
277void ChainedIncludesSource::ForgetSema() {
278  return getFinalReader().ForgetSema();
279}
280void ChainedIncludesSource::ReadMethodPool(Selector Sel) {
281  getFinalReader().ReadMethodPool(Sel);
282}
283bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
284  return getFinalReader().LookupUnqualified(R, S);
285}
286
287