Path: blob/main/contrib/llvm-project/clang/lib/Frontend/ChainedIncludesSource.cpp
35232 views
//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the ChainedIncludesSource class, which converts headers9// to chained PCHs in memory, mainly used for testing.10//11//===----------------------------------------------------------------------===//1213#include "clang/Basic/Builtins.h"14#include "clang/Basic/TargetInfo.h"15#include "clang/Frontend/ASTUnit.h"16#include "clang/Frontend/CompilerInstance.h"17#include "clang/Frontend/TextDiagnosticPrinter.h"18#include "clang/Lex/Preprocessor.h"19#include "clang/Lex/PreprocessorOptions.h"20#include "clang/Parse/ParseAST.h"21#include "clang/Sema/MultiplexExternalSemaSource.h"22#include "clang/Serialization/ASTReader.h"23#include "clang/Serialization/ASTWriter.h"24#include "llvm/Support/MemoryBuffer.h"2526using namespace clang;2728namespace {29class ChainedIncludesSource : public ExternalSemaSource {30public:31ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)32: CIs(std::move(CIs)) {}3334protected:35//===--------------------------------------------------------------------===//36// ExternalASTSource interface.37//===--------------------------------------------------------------------===//3839/// Return the amount of memory used by memory buffers, breaking down40/// by heap-backed versus mmap'ed memory.41void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {42for (unsigned i = 0, e = CIs.size(); i != e; ++i) {43if (const ExternalASTSource *eSrc =44CIs[i]->getASTContext().getExternalSource()) {45eSrc->getMemoryBufferSizes(sizes);46}47}48}4950private:51std::vector<std::unique_ptr<CompilerInstance>> CIs;52};53} // end anonymous namespace5455static ASTReader *56createASTReader(CompilerInstance &CI, StringRef pchFile,57SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,58SmallVectorImpl<std::string> &bufNames,59ASTDeserializationListener *deserialListener = nullptr) {60Preprocessor &PP = CI.getPreprocessor();61std::unique_ptr<ASTReader> Reader;62Reader.reset(new ASTReader(63PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(),64/*Extensions=*/{},65/*isysroot=*/"", DisableValidationForModuleKind::PCH));66for (unsigned ti = 0; ti < bufNames.size(); ++ti) {67StringRef sr(bufNames[ti]);68Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));69}70Reader->setDeserializationListener(deserialListener);71switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),72ASTReader::ARR_None)) {73case ASTReader::Success:74// Set the predefines buffer as suggested by the PCH reader.75PP.setPredefines(Reader->getSuggestedPredefines());76return Reader.release();7778case ASTReader::Failure:79case ASTReader::Missing:80case ASTReader::OutOfDate:81case ASTReader::VersionMismatch:82case ASTReader::ConfigurationMismatch:83case ASTReader::HadErrors:84break;85}86return nullptr;87}8889IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(90CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {9192std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;93assert(!includes.empty() && "No '-chain-include' in options!");9495std::vector<std::unique_ptr<CompilerInstance>> CIs;96InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();9798SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;99SmallVector<std::string, 4> serialBufNames;100101for (unsigned i = 0, e = includes.size(); i != e; ++i) {102bool firstInclude = (i == 0);103std::unique_ptr<CompilerInvocation> CInvok;104CInvok.reset(new CompilerInvocation(CI.getInvocation()));105106CInvok->getPreprocessorOpts().ChainedIncludes.clear();107CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();108CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =109DisableValidationForModuleKind::PCH;110CInvok->getPreprocessorOpts().Includes.clear();111CInvok->getPreprocessorOpts().MacroIncludes.clear();112CInvok->getPreprocessorOpts().Macros.clear();113114CInvok->getFrontendOpts().Inputs.clear();115FrontendInputFile InputFile(includes[i], IK);116CInvok->getFrontendOpts().Inputs.push_back(InputFile);117118TextDiagnosticPrinter *DiagClient =119new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());120IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());121IntrusiveRefCntPtr<DiagnosticsEngine> Diags(122new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));123124std::unique_ptr<CompilerInstance> Clang(125new CompilerInstance(CI.getPCHContainerOperations()));126Clang->setInvocation(std::move(CInvok));127Clang->setDiagnostics(Diags.get());128Clang->setTarget(TargetInfo::CreateTargetInfo(129Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));130Clang->createFileManager();131Clang->createSourceManager(Clang->getFileManager());132Clang->createPreprocessor(TU_Prefix);133Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),134&Clang->getPreprocessor());135Clang->createASTContext();136137auto Buffer = std::make_shared<PCHBuffer>();138ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;139auto consumer = std::make_unique<PCHGenerator>(140Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",141Buffer, Extensions, /*AllowASTWithErrors=*/true);142Clang->getASTContext().setASTMutationListener(143consumer->GetASTMutationListener());144Clang->setASTConsumer(std::move(consumer));145Clang->createSema(TU_Prefix, nullptr);146147if (firstInclude) {148Preprocessor &PP = Clang->getPreprocessor();149PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),150PP.getLangOpts());151} else {152assert(!SerialBufs.empty());153SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;154// TODO: Pass through the existing MemoryBuffer instances instead of155// allocating new ones.156for (auto &SB : SerialBufs)157Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));158std::string pchName = includes[i-1];159llvm::raw_string_ostream os(pchName);160os << ".pch" << i-1;161serialBufNames.push_back(os.str());162163IntrusiveRefCntPtr<ASTReader> Reader;164Reader = createASTReader(165*Clang, pchName, Bufs, serialBufNames,166Clang->getASTConsumer().GetASTDeserializationListener());167if (!Reader)168return nullptr;169Clang->setASTReader(Reader);170Clang->getASTContext().setExternalSource(Reader);171}172173if (!Clang->InitializeSourceManager(InputFile))174return nullptr;175176ParseAST(Clang->getSema());177Clang->getDiagnosticClient().EndSourceFile();178assert(Buffer->IsComplete && "serialization did not complete");179auto &serialAST = Buffer->Data;180SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(181StringRef(serialAST.data(), serialAST.size())));182serialAST.clear();183CIs.push_back(std::move(Clang));184}185186assert(!SerialBufs.empty());187std::string pchName = includes.back() + ".pch-final";188serialBufNames.push_back(pchName);189Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);190if (!Reader)191return nullptr;192193auto ChainedSrc =194llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs));195return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(196ChainedSrc.get(), Reader.get());197}198199200