1f887db09SChandler Carruth //===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
2f887db09SChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f887db09SChandler Carruth //
7f887db09SChandler Carruth //===----------------------------------------------------------------------===//
8f887db09SChandler Carruth //
9f887db09SChandler Carruth // This file defines the ChainedIncludesSource class, which converts headers
10f887db09SChandler Carruth // to chained PCHs in memory, mainly used for testing.
11f887db09SChandler Carruth //
12f887db09SChandler Carruth //===----------------------------------------------------------------------===//
13f887db09SChandler Carruth
14979da9a4SReid Kleckner #include "clang/Basic/Builtins.h"
153a02247dSChandler Carruth #include "clang/Basic/TargetInfo.h"
16f887db09SChandler Carruth #include "clang/Frontend/ASTUnit.h"
173a02247dSChandler Carruth #include "clang/Frontend/CompilerInstance.h"
183a02247dSChandler Carruth #include "clang/Frontend/TextDiagnosticPrinter.h"
193a02247dSChandler Carruth #include "clang/Lex/Preprocessor.h"
209670f847SMehdi Amini #include "clang/Lex/PreprocessorOptions.h"
213a02247dSChandler Carruth #include "clang/Parse/ParseAST.h"
2221b3a032SRichard Smith #include "clang/Sema/MultiplexExternalSemaSource.h"
23f887db09SChandler Carruth #include "clang/Serialization/ASTReader.h"
24f887db09SChandler Carruth #include "clang/Serialization/ASTWriter.h"
25f887db09SChandler Carruth #include "llvm/Support/MemoryBuffer.h"
26f887db09SChandler Carruth
27f887db09SChandler Carruth using namespace clang;
28f887db09SChandler Carruth
299e0523d7SAlp Toker namespace {
3021b3a032SRichard Smith class ChainedIncludesSourceImpl : public ExternalSemaSource {
319e0523d7SAlp Toker public:
ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)3221b3a032SRichard Smith ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)
3321b3a032SRichard Smith : CIs(std::move(CIs)) {}
349e0523d7SAlp Toker
359e0523d7SAlp Toker protected:
369e0523d7SAlp Toker //===----------------------------------------------------------------------===//
379e0523d7SAlp Toker // ExternalASTSource interface.
389e0523d7SAlp Toker //===----------------------------------------------------------------------===//
399e0523d7SAlp Toker
409e0523d7SAlp Toker /// Return the amount of memory used by memory buffers, breaking down
419e0523d7SAlp Toker /// by heap-backed versus mmap'ed memory.
getMemoryBufferSizes(MemoryBufferSizes & sizes) const4221b3a032SRichard Smith void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
4321b3a032SRichard Smith for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
4421b3a032SRichard Smith if (const ExternalASTSource *eSrc =
4521b3a032SRichard Smith CIs[i]->getASTContext().getExternalSource()) {
4621b3a032SRichard Smith eSrc->getMemoryBufferSizes(sizes);
4721b3a032SRichard Smith }
4821b3a032SRichard Smith }
4921b3a032SRichard Smith }
509e0523d7SAlp Toker
5121b3a032SRichard Smith private:
5221b3a032SRichard Smith std::vector<std::unique_ptr<CompilerInstance>> CIs;
5321b3a032SRichard Smith };
549e0523d7SAlp Toker
5521b3a032SRichard Smith /// Members of ChainedIncludesSource, factored out so we can initialize
5621b3a032SRichard Smith /// them before we initialize the ExternalSemaSource base class.
5721b3a032SRichard Smith struct ChainedIncludesSourceMembers {
ChainedIncludesSourceMembers__anonb78b81ad0111::ChainedIncludesSourceMembers585eb7e1bfSRichard Smith ChainedIncludesSourceMembers(
595eb7e1bfSRichard Smith std::vector<std::unique_ptr<CompilerInstance>> CIs,
605eb7e1bfSRichard Smith IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
615eb7e1bfSRichard Smith : Impl(std::move(CIs)), FinalReader(std::move(FinalReader)) {}
6221b3a032SRichard Smith ChainedIncludesSourceImpl Impl;
6321b3a032SRichard Smith IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
6421b3a032SRichard Smith };
6521b3a032SRichard Smith
6621b3a032SRichard Smith /// Use MultiplexExternalSemaSource to dispatch all ExternalSemaSource
6721b3a032SRichard Smith /// calls to the final reader.
6821b3a032SRichard Smith class ChainedIncludesSource
6921b3a032SRichard Smith : private ChainedIncludesSourceMembers,
7021b3a032SRichard Smith public MultiplexExternalSemaSource {
7121b3a032SRichard Smith public:
ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)7221b3a032SRichard Smith ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,
7321b3a032SRichard Smith IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
745eb7e1bfSRichard Smith : ChainedIncludesSourceMembers(std::move(CIs), std::move(FinalReader)),
7521b3a032SRichard Smith MultiplexExternalSemaSource(Impl, *this->FinalReader) {}
769e0523d7SAlp Toker };
77ab9db510SAlexander Kornienko }
789e0523d7SAlp Toker
7949a2790fSCraig Topper static ASTReader *
createASTReader(CompilerInstance & CI,StringRef pchFile,SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> & MemBufs,SmallVectorImpl<std::string> & bufNames,ASTDeserializationListener * deserialListener=nullptr)8049a2790fSCraig Topper createASTReader(CompilerInstance &CI, StringRef pchFile,
815cd06f26SRafael Espindola SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
825603df45SCraig Topper SmallVectorImpl<std::string> &bufNames,
8349a2790fSCraig Topper ASTDeserializationListener *deserialListener = nullptr) {
84f887db09SChandler Carruth Preprocessor &PP = CI.getPreprocessor();
85b8984329SAhmed Charles std::unique_ptr<ASTReader> Reader;
86*b0e89906SArgyrios Kyrtzidis Reader.reset(new ASTReader(
87*b0e89906SArgyrios Kyrtzidis PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(),
886623e1f1SDouglas Gregor /*Extensions=*/{},
89*b0e89906SArgyrios Kyrtzidis /*isysroot=*/"", DisableValidationForModuleKind::PCH));
90f887db09SChandler Carruth for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
91f887db09SChandler Carruth StringRef sr(bufNames[ti]);
925cd06f26SRafael Espindola Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
93f887db09SChandler Carruth }
94f887db09SChandler Carruth Reader->setDeserializationListener(deserialListener);
952ec29367SArgyrios Kyrtzidis switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
964b29c16eSDouglas Gregor ASTReader::ARR_None)) {
97f887db09SChandler Carruth case ASTReader::Success:
98f887db09SChandler Carruth // Set the predefines buffer as suggested by the PCH reader.
99f887db09SChandler Carruth PP.setPredefines(Reader->getSuggestedPredefines());
1009a16beb8SAhmed Charles return Reader.release();
101f887db09SChandler Carruth
102f887db09SChandler Carruth case ASTReader::Failure:
1037029ce1aSDouglas Gregor case ASTReader::Missing:
104c9ad5fb6SDouglas Gregor case ASTReader::OutOfDate:
105c9ad5fb6SDouglas Gregor case ASTReader::VersionMismatch:
106c9ad5fb6SDouglas Gregor case ASTReader::ConfigurationMismatch:
107c9ad5fb6SDouglas Gregor case ASTReader::HadErrors:
108f887db09SChandler Carruth break;
109f887db09SChandler Carruth }
11049a2790fSCraig Topper return nullptr;
111f887db09SChandler Carruth }
112f887db09SChandler Carruth
createChainedIncludesSource(CompilerInstance & CI,IntrusiveRefCntPtr<ExternalSemaSource> & Reader)1139e0523d7SAlp Toker IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
1149e0523d7SAlp Toker CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
115f887db09SChandler Carruth
116f887db09SChandler Carruth std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
117f887db09SChandler Carruth assert(!includes.empty() && "No '-chain-include' in options!");
118f887db09SChandler Carruth
11921b3a032SRichard Smith std::vector<std::unique_ptr<CompilerInstance>> CIs;
120873c8583SArgyrios Kyrtzidis InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
121f887db09SChandler Carruth
1225cd06f26SRafael Espindola SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
123f887db09SChandler Carruth SmallVector<std::string, 4> serialBufNames;
124f887db09SChandler Carruth
125f887db09SChandler Carruth for (unsigned i = 0, e = includes.size(); i != e; ++i) {
126f887db09SChandler Carruth bool firstInclude = (i == 0);
127b8984329SAhmed Charles std::unique_ptr<CompilerInvocation> CInvok;
128f887db09SChandler Carruth CInvok.reset(new CompilerInvocation(CI.getInvocation()));
129f887db09SChandler Carruth
130f887db09SChandler Carruth CInvok->getPreprocessorOpts().ChainedIncludes.clear();
131f887db09SChandler Carruth CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
132*b0e89906SArgyrios Kyrtzidis CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =
133*b0e89906SArgyrios Kyrtzidis DisableValidationForModuleKind::PCH;
134f887db09SChandler Carruth CInvok->getPreprocessorOpts().Includes.clear();
135f887db09SChandler Carruth CInvok->getPreprocessorOpts().MacroIncludes.clear();
136f887db09SChandler Carruth CInvok->getPreprocessorOpts().Macros.clear();
137f887db09SChandler Carruth
138f887db09SChandler Carruth CInvok->getFrontendOpts().Inputs.clear();
1391b3240b0SArgyrios Kyrtzidis FrontendInputFile InputFile(includes[i], IK);
1401b3240b0SArgyrios Kyrtzidis CInvok->getFrontendOpts().Inputs.push_back(InputFile);
141f887db09SChandler Carruth
142f887db09SChandler Carruth TextDiagnosticPrinter *DiagClient =
143811db4eaSDouglas Gregor new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
144c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
145c95d8192SDylan Noblesmith IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
146811db4eaSDouglas Gregor new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
147f887db09SChandler Carruth
148bb165fb0SAdrian Prantl std::unique_ptr<CompilerInstance> Clang(
149bb165fb0SAdrian Prantl new CompilerInstance(CI.getPCHContainerOperations()));
150ea4395ebSDavid Blaikie Clang->setInvocation(std::move(CInvok));
151f994cef8SAlp Toker Clang->setDiagnostics(Diags.get());
15280758084SAlp Toker Clang->setTarget(TargetInfo::CreateTargetInfo(
15310a4972aSSaleem Abdulrasool Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
154f887db09SChandler Carruth Clang->createFileManager();
155f887db09SChandler Carruth Clang->createSourceManager(Clang->getFileManager());
156e1974dcdSArgyrios Kyrtzidis Clang->createPreprocessor(TU_Prefix);
157f887db09SChandler Carruth Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
158f887db09SChandler Carruth &Clang->getPreprocessor());
159f887db09SChandler Carruth Clang->createASTContext();
160f887db09SChandler Carruth
161bb165fb0SAdrian Prantl auto Buffer = std::make_shared<PCHBuffer>();
16261137e1aSDavid Blaikie ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;
1632b3d49b6SJonas Devlieghere auto consumer = std::make_unique<PCHGenerator>(
1648bef5cd4SDuncan P. N. Exon Smith Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
1658bef5cd4SDuncan P. N. Exon Smith Buffer, Extensions, /*AllowASTWithErrors=*/true);
166f887db09SChandler Carruth Clang->getASTContext().setASTMutationListener(
167f887db09SChandler Carruth consumer->GetASTMutationListener());
1686beb6aa8SDavid Blaikie Clang->setASTConsumer(std::move(consumer));
16949a2790fSCraig Topper Clang->createSema(TU_Prefix, nullptr);
170f887db09SChandler Carruth
171f887db09SChandler Carruth if (firstInclude) {
172f887db09SChandler Carruth Preprocessor &PP = Clang->getPreprocessor();
17302d5d86bSEric Christopher PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
174bbafb8a7SDavid Blaikie PP.getLangOpts());
175f887db09SChandler Carruth } else {
1765cd06f26SRafael Espindola assert(!SerialBufs.empty());
1775cd06f26SRafael Espindola SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
1787eb95e21SAlp Toker // TODO: Pass through the existing MemoryBuffer instances instead of
1797eb95e21SAlp Toker // allocating new ones.
1805cd06f26SRafael Espindola for (auto &SB : SerialBufs)
181d87f8d76SRafael Espindola Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
182f887db09SChandler Carruth std::string pchName = includes[i-1];
183f887db09SChandler Carruth llvm::raw_string_ostream os(pchName);
184f887db09SChandler Carruth os << ".pch" << i-1;
1857eb95e21SAlp Toker serialBufNames.push_back(os.str());
186f887db09SChandler Carruth
1871b7ed91eSArgyrios Kyrtzidis IntrusiveRefCntPtr<ASTReader> Reader;
1885cd06f26SRafael Espindola Reader = createASTReader(
1895cd06f26SRafael Espindola *Clang, pchName, Bufs, serialBufNames,
1901b7ed91eSArgyrios Kyrtzidis Clang->getASTConsumer().GetASTDeserializationListener());
191f887db09SChandler Carruth if (!Reader)
19249a2790fSCraig Topper return nullptr;
193a6c86989SVolodymyr Sapsai Clang->setASTReader(Reader);
194f887db09SChandler Carruth Clang->getASTContext().setExternalSource(Reader);
195f887db09SChandler Carruth }
196f887db09SChandler Carruth
1971b3240b0SArgyrios Kyrtzidis if (!Clang->InitializeSourceManager(InputFile))
19849a2790fSCraig Topper return nullptr;
199f887db09SChandler Carruth
200f887db09SChandler Carruth ParseAST(Clang->getSema());
201f887db09SChandler Carruth Clang->getDiagnosticClient().EndSourceFile();
202bb165fb0SAdrian Prantl assert(Buffer->IsComplete && "serialization did not complete");
203bb165fb0SAdrian Prantl auto &serialAST = Buffer->Data;
204bb165fb0SAdrian Prantl SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
205bb165fb0SAdrian Prantl StringRef(serialAST.data(), serialAST.size())));
206bb165fb0SAdrian Prantl serialAST.clear();
20721b3a032SRichard Smith CIs.push_back(std::move(Clang));
208f887db09SChandler Carruth }
209f887db09SChandler Carruth
2105cd06f26SRafael Espindola assert(!SerialBufs.empty());
211f887db09SChandler Carruth std::string pchName = includes.back() + ".pch-final";
212f887db09SChandler Carruth serialBufNames.push_back(pchName);
2135cd06f26SRafael Espindola Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
214f887db09SChandler Carruth if (!Reader)
21549a2790fSCraig Topper return nullptr;
216f887db09SChandler Carruth
21721b3a032SRichard Smith return IntrusiveRefCntPtr<ChainedIncludesSource>(
21821b3a032SRichard Smith new ChainedIncludesSource(std::move(CIs), Reader));
219f887db09SChandler Carruth }
220