10b57cec5SDimitry Andric //===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the ChainedIncludesSource class, which converts headers
100b57cec5SDimitry Andric // to chained PCHs in memory, mainly used for testing.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
14480093f4SDimitry Andric #include "clang/Basic/Builtins.h"
150b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
160b57cec5SDimitry Andric #include "clang/Frontend/ASTUnit.h"
170b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
180b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
190b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
200b57cec5SDimitry Andric #include "clang/Lex/PreprocessorOptions.h"
210b57cec5SDimitry Andric #include "clang/Parse/ParseAST.h"
220b57cec5SDimitry Andric #include "clang/Sema/MultiplexExternalSemaSource.h"
230b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h"
240b57cec5SDimitry Andric #include "clang/Serialization/ASTWriter.h"
250b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric namespace {
30*bdd1243dSDimitry Andric class ChainedIncludesSource : public ExternalSemaSource {
310b57cec5SDimitry Andric public:
ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)32*bdd1243dSDimitry Andric ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)
330b57cec5SDimitry Andric : CIs(std::move(CIs)) {}
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric protected:
36*bdd1243dSDimitry Andric //===--------------------------------------------------------------------===//
370b57cec5SDimitry Andric // ExternalASTSource interface.
38*bdd1243dSDimitry Andric //===--------------------------------------------------------------------===//
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric /// Return the amount of memory used by memory buffers, breaking down
410b57cec5SDimitry Andric /// by heap-backed versus mmap'ed memory.
getMemoryBufferSizes(MemoryBufferSizes & sizes) const420b57cec5SDimitry Andric void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
430b57cec5SDimitry Andric for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
440b57cec5SDimitry Andric if (const ExternalASTSource *eSrc =
450b57cec5SDimitry Andric CIs[i]->getASTContext().getExternalSource()) {
460b57cec5SDimitry Andric eSrc->getMemoryBufferSizes(sizes);
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric private:
520b57cec5SDimitry Andric std::vector<std::unique_ptr<CompilerInstance>> CIs;
530b57cec5SDimitry Andric };
54*bdd1243dSDimitry Andric } // end anonymous namespace
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric static ASTReader *
createASTReader(CompilerInstance & CI,StringRef pchFile,SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> & MemBufs,SmallVectorImpl<std::string> & bufNames,ASTDeserializationListener * deserialListener=nullptr)570b57cec5SDimitry Andric createASTReader(CompilerInstance &CI, StringRef pchFile,
580b57cec5SDimitry Andric SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
590b57cec5SDimitry Andric SmallVectorImpl<std::string> &bufNames,
600b57cec5SDimitry Andric ASTDeserializationListener *deserialListener = nullptr) {
610b57cec5SDimitry Andric Preprocessor &PP = CI.getPreprocessor();
620b57cec5SDimitry Andric std::unique_ptr<ASTReader> Reader;
63e8d8bef9SDimitry Andric Reader.reset(new ASTReader(
64e8d8bef9SDimitry Andric PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(),
650b57cec5SDimitry Andric /*Extensions=*/{},
66e8d8bef9SDimitry Andric /*isysroot=*/"", DisableValidationForModuleKind::PCH));
670b57cec5SDimitry Andric for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
680b57cec5SDimitry Andric StringRef sr(bufNames[ti]);
690b57cec5SDimitry Andric Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric Reader->setDeserializationListener(deserialListener);
720b57cec5SDimitry Andric switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
730b57cec5SDimitry Andric ASTReader::ARR_None)) {
740b57cec5SDimitry Andric case ASTReader::Success:
750b57cec5SDimitry Andric // Set the predefines buffer as suggested by the PCH reader.
760b57cec5SDimitry Andric PP.setPredefines(Reader->getSuggestedPredefines());
770b57cec5SDimitry Andric return Reader.release();
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric case ASTReader::Failure:
800b57cec5SDimitry Andric case ASTReader::Missing:
810b57cec5SDimitry Andric case ASTReader::OutOfDate:
820b57cec5SDimitry Andric case ASTReader::VersionMismatch:
830b57cec5SDimitry Andric case ASTReader::ConfigurationMismatch:
840b57cec5SDimitry Andric case ASTReader::HadErrors:
850b57cec5SDimitry Andric break;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric return nullptr;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric
createChainedIncludesSource(CompilerInstance & CI,IntrusiveRefCntPtr<ExternalSemaSource> & Reader)900b57cec5SDimitry Andric IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
910b57cec5SDimitry Andric CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
940b57cec5SDimitry Andric assert(!includes.empty() && "No '-chain-include' in options!");
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric std::vector<std::unique_ptr<CompilerInstance>> CIs;
970b57cec5SDimitry Andric InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
1000b57cec5SDimitry Andric SmallVector<std::string, 4> serialBufNames;
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric for (unsigned i = 0, e = includes.size(); i != e; ++i) {
1030b57cec5SDimitry Andric bool firstInclude = (i == 0);
1040b57cec5SDimitry Andric std::unique_ptr<CompilerInvocation> CInvok;
1050b57cec5SDimitry Andric CInvok.reset(new CompilerInvocation(CI.getInvocation()));
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric CInvok->getPreprocessorOpts().ChainedIncludes.clear();
1080b57cec5SDimitry Andric CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
109e8d8bef9SDimitry Andric CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =
110e8d8bef9SDimitry Andric DisableValidationForModuleKind::PCH;
1110b57cec5SDimitry Andric CInvok->getPreprocessorOpts().Includes.clear();
1120b57cec5SDimitry Andric CInvok->getPreprocessorOpts().MacroIncludes.clear();
1130b57cec5SDimitry Andric CInvok->getPreprocessorOpts().Macros.clear();
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric CInvok->getFrontendOpts().Inputs.clear();
1160b57cec5SDimitry Andric FrontendInputFile InputFile(includes[i], IK);
1170b57cec5SDimitry Andric CInvok->getFrontendOpts().Inputs.push_back(InputFile);
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric TextDiagnosticPrinter *DiagClient =
1200b57cec5SDimitry Andric new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
1210b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
1220b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
1230b57cec5SDimitry Andric new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric std::unique_ptr<CompilerInstance> Clang(
1260b57cec5SDimitry Andric new CompilerInstance(CI.getPCHContainerOperations()));
1270b57cec5SDimitry Andric Clang->setInvocation(std::move(CInvok));
1280b57cec5SDimitry Andric Clang->setDiagnostics(Diags.get());
1290b57cec5SDimitry Andric Clang->setTarget(TargetInfo::CreateTargetInfo(
1300b57cec5SDimitry Andric Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
1310b57cec5SDimitry Andric Clang->createFileManager();
1320b57cec5SDimitry Andric Clang->createSourceManager(Clang->getFileManager());
1330b57cec5SDimitry Andric Clang->createPreprocessor(TU_Prefix);
1340b57cec5SDimitry Andric Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
1350b57cec5SDimitry Andric &Clang->getPreprocessor());
1360b57cec5SDimitry Andric Clang->createASTContext();
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric auto Buffer = std::make_shared<PCHBuffer>();
1390b57cec5SDimitry Andric ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;
140a7dea167SDimitry Andric auto consumer = std::make_unique<PCHGenerator>(
1410b57cec5SDimitry Andric Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
1420b57cec5SDimitry Andric Buffer, Extensions, /*AllowASTWithErrors=*/true);
1430b57cec5SDimitry Andric Clang->getASTContext().setASTMutationListener(
1440b57cec5SDimitry Andric consumer->GetASTMutationListener());
1450b57cec5SDimitry Andric Clang->setASTConsumer(std::move(consumer));
1460b57cec5SDimitry Andric Clang->createSema(TU_Prefix, nullptr);
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric if (firstInclude) {
1490b57cec5SDimitry Andric Preprocessor &PP = Clang->getPreprocessor();
1500b57cec5SDimitry Andric PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
1510b57cec5SDimitry Andric PP.getLangOpts());
1520b57cec5SDimitry Andric } else {
1530b57cec5SDimitry Andric assert(!SerialBufs.empty());
1540b57cec5SDimitry Andric SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
1550b57cec5SDimitry Andric // TODO: Pass through the existing MemoryBuffer instances instead of
1560b57cec5SDimitry Andric // allocating new ones.
1570b57cec5SDimitry Andric for (auto &SB : SerialBufs)
1580b57cec5SDimitry Andric Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
1590b57cec5SDimitry Andric std::string pchName = includes[i-1];
1600b57cec5SDimitry Andric llvm::raw_string_ostream os(pchName);
1610b57cec5SDimitry Andric os << ".pch" << i-1;
1620b57cec5SDimitry Andric serialBufNames.push_back(os.str());
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric IntrusiveRefCntPtr<ASTReader> Reader;
1650b57cec5SDimitry Andric Reader = createASTReader(
1660b57cec5SDimitry Andric *Clang, pchName, Bufs, serialBufNames,
1670b57cec5SDimitry Andric Clang->getASTConsumer().GetASTDeserializationListener());
1680b57cec5SDimitry Andric if (!Reader)
1690b57cec5SDimitry Andric return nullptr;
1705ffd83dbSDimitry Andric Clang->setASTReader(Reader);
1710b57cec5SDimitry Andric Clang->getASTContext().setExternalSource(Reader);
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric if (!Clang->InitializeSourceManager(InputFile))
1750b57cec5SDimitry Andric return nullptr;
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric ParseAST(Clang->getSema());
1780b57cec5SDimitry Andric Clang->getDiagnosticClient().EndSourceFile();
1790b57cec5SDimitry Andric assert(Buffer->IsComplete && "serialization did not complete");
1800b57cec5SDimitry Andric auto &serialAST = Buffer->Data;
1810b57cec5SDimitry Andric SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
1820b57cec5SDimitry Andric StringRef(serialAST.data(), serialAST.size())));
1830b57cec5SDimitry Andric serialAST.clear();
1840b57cec5SDimitry Andric CIs.push_back(std::move(Clang));
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric assert(!SerialBufs.empty());
1880b57cec5SDimitry Andric std::string pchName = includes.back() + ".pch-final";
1890b57cec5SDimitry Andric serialBufNames.push_back(pchName);
1900b57cec5SDimitry Andric Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
1910b57cec5SDimitry Andric if (!Reader)
1920b57cec5SDimitry Andric return nullptr;
1930b57cec5SDimitry Andric
194*bdd1243dSDimitry Andric auto ChainedSrc =
195*bdd1243dSDimitry Andric llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs));
196*bdd1243dSDimitry Andric return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(
197*bdd1243dSDimitry Andric ChainedSrc.get(), Reader.get());
1980b57cec5SDimitry Andric }
199