1234287Sdim//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
2234287Sdim//
3234287Sdim//                     The LLVM Compiler Infrastructure
4234287Sdim//
5234287Sdim// This file is distributed under the University of Illinois Open Source
6234287Sdim// License. See LICENSE.TXT for details.
7234287Sdim//
8234287Sdim//===----------------------------------------------------------------------===//
9234287Sdim//
10234287Sdim//  This file defines the ChainedIncludesSource class, which converts headers
11234287Sdim//  to chained PCHs in memory, mainly used for testing.
12234287Sdim//
13234287Sdim//===----------------------------------------------------------------------===//
14234287Sdim
15234287Sdim#include "clang/Frontend/ChainedIncludesSource.h"
16249423Sdim#include "clang/Basic/TargetInfo.h"
17249423Sdim#include "clang/Frontend/ASTUnit.h"
18249423Sdim#include "clang/Frontend/CompilerInstance.h"
19234287Sdim#include "clang/Frontend/TextDiagnosticPrinter.h"
20249423Sdim#include "clang/Lex/Preprocessor.h"
21249423Sdim#include "clang/Parse/ParseAST.h"
22234287Sdim#include "clang/Serialization/ASTReader.h"
23234287Sdim#include "clang/Serialization/ASTWriter.h"
24234287Sdim#include "llvm/Support/MemoryBuffer.h"
25234287Sdim
26234287Sdimusing namespace clang;
27234287Sdim
28234287Sdimstatic ASTReader *createASTReader(CompilerInstance &CI,
29263508Sdim                             StringRef pchFile,
30263508Sdim                             SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
31263508Sdim                             SmallVectorImpl<std::string> &bufNames,
32234287Sdim                             ASTDeserializationListener *deserialListener = 0) {
33234287Sdim  Preprocessor &PP = CI.getPreprocessor();
34234287Sdim  OwningPtr<ASTReader> Reader;
35234287Sdim  Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
36234287Sdim                             /*DisableValidation=*/true));
37234287Sdim  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
38234287Sdim    StringRef sr(bufNames[ti]);
39234287Sdim    Reader->addInMemoryBuffer(sr, memBufs[ti]);
40234287Sdim  }
41234287Sdim  Reader->setDeserializationListener(deserialListener);
42249423Sdim  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
43243830Sdim                          ASTReader::ARR_None)) {
44234287Sdim  case ASTReader::Success:
45234287Sdim    // Set the predefines buffer as suggested by the PCH reader.
46234287Sdim    PP.setPredefines(Reader->getSuggestedPredefines());
47234287Sdim    return Reader.take();
48234287Sdim
49234287Sdim  case ASTReader::Failure:
50249423Sdim  case ASTReader::Missing:
51243830Sdim  case ASTReader::OutOfDate:
52243830Sdim  case ASTReader::VersionMismatch:
53243830Sdim  case ASTReader::ConfigurationMismatch:
54243830Sdim  case ASTReader::HadErrors:
55234287Sdim    break;
56234287Sdim  }
57234287Sdim  return 0;
58234287Sdim}
59234287Sdim
60234287SdimChainedIncludesSource::~ChainedIncludesSource() {
61234287Sdim  for (unsigned i = 0, e = CIs.size(); i != e; ++i)
62234287Sdim    delete CIs[i];
63234287Sdim}
64234287Sdim
65234287SdimChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
66234287Sdim
67234287Sdim  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
68234287Sdim  assert(!includes.empty() && "No '-chain-include' in options!");
69234287Sdim
70234287Sdim  OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
71243830Sdim  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
72234287Sdim
73234287Sdim  SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
74234287Sdim  SmallVector<std::string, 4> serialBufNames;
75234287Sdim
76234287Sdim  for (unsigned i = 0, e = includes.size(); i != e; ++i) {
77234287Sdim    bool firstInclude = (i == 0);
78234287Sdim    OwningPtr<CompilerInvocation> CInvok;
79234287Sdim    CInvok.reset(new CompilerInvocation(CI.getInvocation()));
80234287Sdim
81234287Sdim    CInvok->getPreprocessorOpts().ChainedIncludes.clear();
82234287Sdim    CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
83234287Sdim    CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
84234287Sdim    CInvok->getPreprocessorOpts().DisablePCHValidation = true;
85234287Sdim    CInvok->getPreprocessorOpts().Includes.clear();
86234287Sdim    CInvok->getPreprocessorOpts().MacroIncludes.clear();
87234287Sdim    CInvok->getPreprocessorOpts().Macros.clear();
88234287Sdim
89234287Sdim    CInvok->getFrontendOpts().Inputs.clear();
90243830Sdim    FrontendInputFile InputFile(includes[i], IK);
91243830Sdim    CInvok->getFrontendOpts().Inputs.push_back(InputFile);
92234287Sdim
93234287Sdim    TextDiagnosticPrinter *DiagClient =
94243830Sdim      new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
95234287Sdim    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
96234287Sdim    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
97243830Sdim        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
98234287Sdim
99234287Sdim    OwningPtr<CompilerInstance> Clang(new CompilerInstance());
100234287Sdim    Clang->setInvocation(CInvok.take());
101234287Sdim    Clang->setDiagnostics(Diags.getPtr());
102234287Sdim    Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
103249423Sdim                                                  &Clang->getTargetOpts()));
104234287Sdim    Clang->createFileManager();
105234287Sdim    Clang->createSourceManager(Clang->getFileManager());
106234287Sdim    Clang->createPreprocessor();
107234287Sdim    Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
108234287Sdim                                                 &Clang->getPreprocessor());
109234287Sdim    Clang->createASTContext();
110234287Sdim
111234287Sdim    SmallVector<char, 256> serialAST;
112234287Sdim    llvm::raw_svector_ostream OS(serialAST);
113234287Sdim    OwningPtr<ASTConsumer> consumer;
114234287Sdim    consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
115234287Sdim                                    /*isysroot=*/"", &OS));
116234287Sdim    Clang->getASTContext().setASTMutationListener(
117234287Sdim                                            consumer->GetASTMutationListener());
118234287Sdim    Clang->setASTConsumer(consumer.take());
119234287Sdim    Clang->createSema(TU_Prefix, 0);
120234287Sdim
121234287Sdim    if (firstInclude) {
122234287Sdim      Preprocessor &PP = Clang->getPreprocessor();
123234287Sdim      PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
124234287Sdim                                             PP.getLangOpts());
125234287Sdim    } else {
126234287Sdim      assert(!serialBufs.empty());
127234287Sdim      SmallVector<llvm::MemoryBuffer *, 4> bufs;
128234287Sdim      for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) {
129234287Sdim        bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
130234287Sdim                             StringRef(serialBufs[si]->getBufferStart(),
131234287Sdim                                             serialBufs[si]->getBufferSize())));
132234287Sdim      }
133234287Sdim      std::string pchName = includes[i-1];
134234287Sdim      llvm::raw_string_ostream os(pchName);
135234287Sdim      os << ".pch" << i-1;
136234287Sdim      os.flush();
137234287Sdim
138234287Sdim      serialBufNames.push_back(pchName);
139234287Sdim
140234287Sdim      OwningPtr<ExternalASTSource> Reader;
141234287Sdim
142234287Sdim      Reader.reset(createASTReader(*Clang, pchName, bufs, serialBufNames,
143234287Sdim        Clang->getASTConsumer().GetASTDeserializationListener()));
144234287Sdim      if (!Reader)
145234287Sdim        return 0;
146251662Sdim      Clang->setModuleManager(static_cast<ASTReader*>(Reader.get()));
147234287Sdim      Clang->getASTContext().setExternalSource(Reader);
148234287Sdim    }
149234287Sdim
150243830Sdim    if (!Clang->InitializeSourceManager(InputFile))
151234287Sdim      return 0;
152234287Sdim
153234287Sdim    ParseAST(Clang->getSema());
154234287Sdim    OS.flush();
155234287Sdim    Clang->getDiagnosticClient().EndSourceFile();
156234287Sdim    serialBufs.push_back(
157234287Sdim      llvm::MemoryBuffer::getMemBufferCopy(StringRef(serialAST.data(),
158234287Sdim                                                           serialAST.size())));
159234287Sdim    source->CIs.push_back(Clang.take());
160234287Sdim  }
161234287Sdim
162234287Sdim  assert(!serialBufs.empty());
163234287Sdim  std::string pchName = includes.back() + ".pch-final";
164234287Sdim  serialBufNames.push_back(pchName);
165234287Sdim  OwningPtr<ASTReader> Reader;
166234287Sdim  Reader.reset(createASTReader(CI, pchName, serialBufs, serialBufNames));
167234287Sdim  if (!Reader)
168234287Sdim    return 0;
169234287Sdim
170234287Sdim  source->FinalReader.reset(Reader.take());
171234287Sdim  return source.take();
172234287Sdim}
173234287Sdim
174234287Sdim//===----------------------------------------------------------------------===//
175234287Sdim// ExternalASTSource interface.
176234287Sdim//===----------------------------------------------------------------------===//
177234287Sdim
178234287SdimDecl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
179234287Sdim  return getFinalReader().GetExternalDecl(ID);
180234287Sdim}
181234287SdimSelector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
182234287Sdim  return getFinalReader().GetExternalSelector(ID);
183234287Sdim}
184234287Sdimuint32_t ChainedIncludesSource::GetNumExternalSelectors() {
185234287Sdim  return getFinalReader().GetNumExternalSelectors();
186234287Sdim}
187234287SdimStmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
188234287Sdim  return getFinalReader().GetExternalDeclStmt(Offset);
189234287Sdim}
190234287SdimCXXBaseSpecifier *
191234287SdimChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
192234287Sdim  return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
193234287Sdim}
194249423Sdimbool
195234287SdimChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
196234287Sdim                                                      DeclarationName Name) {
197234287Sdim  return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
198234287Sdim}
199234287SdimExternalLoadResult
200234287SdimChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
201234287Sdim                                      bool (*isKindWeWant)(Decl::Kind),
202234287Sdim                                      SmallVectorImpl<Decl*> &Result) {
203234287Sdim  return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
204234287Sdim}
205234287Sdimvoid ChainedIncludesSource::CompleteType(TagDecl *Tag) {
206234287Sdim  return getFinalReader().CompleteType(Tag);
207234287Sdim}
208234287Sdimvoid ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
209234287Sdim  return getFinalReader().CompleteType(Class);
210234287Sdim}
211234287Sdimvoid ChainedIncludesSource::StartedDeserializing() {
212234287Sdim  return getFinalReader().StartedDeserializing();
213234287Sdim}
214234287Sdimvoid ChainedIncludesSource::FinishedDeserializing() {
215234287Sdim  return getFinalReader().FinishedDeserializing();
216234287Sdim}
217234287Sdimvoid ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
218234287Sdim  return getFinalReader().StartTranslationUnit(Consumer);
219234287Sdim}
220234287Sdimvoid ChainedIncludesSource::PrintStats() {
221234287Sdim  return getFinalReader().PrintStats();
222234287Sdim}
223234287Sdimvoid ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{
224234287Sdim  for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
225234287Sdim    if (const ExternalASTSource *eSrc =
226234287Sdim        CIs[i]->getASTContext().getExternalSource()) {
227234287Sdim      eSrc->getMemoryBufferSizes(sizes);
228234287Sdim    }
229234287Sdim  }
230234287Sdim
231234287Sdim  getFinalReader().getMemoryBufferSizes(sizes);
232234287Sdim}
233234287Sdim
234234287Sdimvoid ChainedIncludesSource::InitializeSema(Sema &S) {
235234287Sdim  return getFinalReader().InitializeSema(S);
236234287Sdim}
237234287Sdimvoid ChainedIncludesSource::ForgetSema() {
238234287Sdim  return getFinalReader().ForgetSema();
239234287Sdim}
240234287Sdimvoid ChainedIncludesSource::ReadMethodPool(Selector Sel) {
241234287Sdim  getFinalReader().ReadMethodPool(Sel);
242234287Sdim}
243234287Sdimbool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
244234287Sdim  return getFinalReader().LookupUnqualified(R, S);
245234287Sdim}
246234287Sdim
247