blob: da34743cee6782c3cc728ac9b34aff88314cfbaa [file] [log] [blame]
Argyrios Kyrtzidisb0f4b9a2011-03-09 17:21:42 +00001//===- 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/Serialization/ChainedIncludesSource.h"
16#include "clang/Serialization/ASTReader.h"
17#include "clang/Serialization/ASTWriter.h"
18#include "clang/Frontend/TextDiagnosticPrinter.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/ASTUnit.h"
21#include "clang/Parse/ParseAST.h"
22#include "clang/Lex/Preprocessor.h"
23#include "clang/Basic/TargetInfo.h"
24#include "llvm/Support/MemoryBuffer.h"
25
26using namespace clang;
27
28static ASTReader *createASTReader(CompilerInstance &CI,
29 llvm::StringRef pchFile,
30 llvm::MemoryBuffer **memBufs,
31 unsigned numBufs,
32 ASTDeserializationListener *deserialListener = 0) {
33 Preprocessor &PP = CI.getPreprocessor();
34 llvm::OwningPtr<ASTReader> Reader;
35 Reader.reset(new ASTReader(PP, &CI.getASTContext(), /*isysroot=*/0,
36 /*DisableValidation=*/true));
37 Reader->setASTMemoryBuffers(memBufs, numBufs);
38 Reader->setDeserializationListener(deserialListener);
39 switch (Reader->ReadAST(pchFile, ASTReader::PCH)) {
40 case ASTReader::Success:
41 // Set the predefines buffer as suggested by the PCH reader.
42 PP.setPredefines(Reader->getSuggestedPredefines());
43 return Reader.take();
44
45 case ASTReader::Failure:
46 case ASTReader::IgnorePCH:
47 break;
48 }
49 return 0;
50}
51
52ChainedIncludesSource::~ChainedIncludesSource() {
53 for (unsigned i = 0, e = CIs.size(); i != e; ++i)
54 delete CIs[i];
55}
56
57ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
58
59 std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
60 assert(!includes.empty() && "No '-chain-include' in options!");
61
62 llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
63 InputKind IK = CI.getFrontendOpts().Inputs[0].first;
64
65 llvm::SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
66
67 for (unsigned i = 0, e = includes.size(); i != e; ++i) {
68 bool firstInclude = (i == 0);
69 llvm::OwningPtr<CompilerInvocation> CInvok;
70 CInvok.reset(new CompilerInvocation(CI.getInvocation()));
71
72 CInvok->getPreprocessorOpts().ChainedIncludes.clear();
73 CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
74 CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
75 CInvok->getPreprocessorOpts().DisablePCHValidation = true;
76 CInvok->getPreprocessorOpts().Includes.clear();
77 CInvok->getPreprocessorOpts().MacroIncludes.clear();
78 CInvok->getPreprocessorOpts().Macros.clear();
79
80 CInvok->getFrontendOpts().Inputs.clear();
81 CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(IK, includes[i]));
82
83 TextDiagnosticPrinter *DiagClient =
84 new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
85 llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
86 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID,
87 DiagClient));
88
89 llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
90 Clang->setInvocation(CInvok.take());
91 Clang->setDiagnostics(Diags.getPtr());
92 Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
93 Clang->getTargetOpts()));
94 Clang->createFileManager();
95 Clang->createSourceManager(Clang->getFileManager());
96 Clang->createPreprocessor();
97 Clang->createASTContext();
98
99 llvm::SmallVector<char, 256> serialAST;
100 llvm::raw_svector_ostream OS(serialAST);
101 llvm::OwningPtr<ASTConsumer> consumer;
102 consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-",
103 /*Chaining=*/!firstInclude,
104 /*isysroot=*/0, &OS));
105 Clang->getASTContext().setASTMutationListener(
106 consumer->GetASTMutationListener());
107 Clang->setASTConsumer(consumer.take());
108 Clang->createSema(/*CompleteTranslationUnit=*/false, 0);
109
110 if (firstInclude) {
111 Preprocessor &PP = Clang->getPreprocessor();
112 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
113 PP.getLangOptions());
114 } else {
115 assert(!serialBufs.empty());
116 llvm::SmallVector<llvm::MemoryBuffer *, 4> bufs;
117 for (unsigned i = 0, e = serialBufs.size(); i != e; ++i) {
118 bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
119 llvm::StringRef(serialBufs[i]->getBufferStart(),
120 serialBufs[i]->getBufferSize())));
121 }
122 std::string pchName = includes[i-1];
123 llvm::raw_string_ostream os(pchName);
124 os << ".pch" << i-1;
125 os.flush();
126 llvm::OwningPtr<ExternalASTSource> Reader;
127 Reader.reset(createASTReader(*Clang, pchName, bufs.data(), bufs.size(),
128 Clang->getASTConsumer().GetASTDeserializationListener()));
129 if (!Reader)
130 return 0;
131 Clang->getASTContext().setExternalSource(Reader);
132 }
133
134 if (!Clang->InitializeSourceManager(includes[i]))
135 return 0;
136
137 ParseAST(Clang->getSema());
138 OS.flush();
139 serialBufs.push_back(
140 llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(serialAST.data(),
141 serialAST.size())));
142 source->CIs.push_back(Clang.take());
143 }
144
145 assert(!serialBufs.empty());
146 std::string pchName = includes.back() + ".pch-final";
147 llvm::OwningPtr<ASTReader> Reader;
148 Reader.reset(createASTReader(CI, pchName,
149 serialBufs.data(), serialBufs.size()));
150 if (!Reader)
151 return 0;
152
153 source->FinalReader.reset(Reader.take());
154 return source.take();
155}
156
157//===----------------------------------------------------------------------===//
158// ExternalASTSource interface.
159//===----------------------------------------------------------------------===//
160
161Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
162 return getFinalReader().GetExternalDecl(ID);
163}
164Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
165 return getFinalReader().GetExternalSelector(ID);
166}
167uint32_t ChainedIncludesSource::GetNumExternalSelectors() {
168 return getFinalReader().GetNumExternalSelectors();
169}
170Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
171 return getFinalReader().GetExternalDeclStmt(Offset);
172}
173CXXBaseSpecifier *
174ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
175 return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
176}
177DeclContextLookupResult
178ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
179 DeclarationName Name) {
180 return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
181}
182void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) {
183 return getFinalReader().MaterializeVisibleDecls(DC);
184}
185bool ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC,
186 bool (*isKindWeWant)(Decl::Kind),
187 llvm::SmallVectorImpl<Decl*> &Result) {
188 return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result);
189}
190void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
191 return getFinalReader().CompleteType(Tag);
192}
193void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
194 return getFinalReader().CompleteType(Class);
195}
196void ChainedIncludesSource::StartedDeserializing() {
197 return getFinalReader().StartedDeserializing();
198}
199void ChainedIncludesSource::FinishedDeserializing() {
200 return getFinalReader().FinishedDeserializing();
201}
202void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
203 return getFinalReader().StartTranslationUnit(Consumer);
204}
205void ChainedIncludesSource::PrintStats() {
206 return getFinalReader().PrintStats();
207}