xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Frontend/ChainedIncludesSource.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg //  This file defines the ChainedIncludesSource class, which converts headers
107330f729Sjoerg //  to chained PCHs in memory, mainly used for testing.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
14*e038c9c4Sjoerg #include "clang/Basic/Builtins.h"
157330f729Sjoerg #include "clang/Basic/TargetInfo.h"
167330f729Sjoerg #include "clang/Frontend/ASTUnit.h"
177330f729Sjoerg #include "clang/Frontend/CompilerInstance.h"
187330f729Sjoerg #include "clang/Frontend/TextDiagnosticPrinter.h"
197330f729Sjoerg #include "clang/Lex/Preprocessor.h"
207330f729Sjoerg #include "clang/Lex/PreprocessorOptions.h"
217330f729Sjoerg #include "clang/Parse/ParseAST.h"
227330f729Sjoerg #include "clang/Sema/MultiplexExternalSemaSource.h"
237330f729Sjoerg #include "clang/Serialization/ASTReader.h"
247330f729Sjoerg #include "clang/Serialization/ASTWriter.h"
257330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
267330f729Sjoerg 
277330f729Sjoerg using namespace clang;
287330f729Sjoerg 
297330f729Sjoerg namespace {
307330f729Sjoerg class ChainedIncludesSourceImpl : public ExternalSemaSource {
317330f729Sjoerg public:
ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)327330f729Sjoerg   ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)
337330f729Sjoerg       : CIs(std::move(CIs)) {}
347330f729Sjoerg 
357330f729Sjoerg protected:
367330f729Sjoerg   //===----------------------------------------------------------------------===//
377330f729Sjoerg   // ExternalASTSource interface.
387330f729Sjoerg   //===----------------------------------------------------------------------===//
397330f729Sjoerg 
407330f729Sjoerg   /// Return the amount of memory used by memory buffers, breaking down
417330f729Sjoerg   /// by heap-backed versus mmap'ed memory.
getMemoryBufferSizes(MemoryBufferSizes & sizes) const427330f729Sjoerg   void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
437330f729Sjoerg     for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
447330f729Sjoerg       if (const ExternalASTSource *eSrc =
457330f729Sjoerg           CIs[i]->getASTContext().getExternalSource()) {
467330f729Sjoerg         eSrc->getMemoryBufferSizes(sizes);
477330f729Sjoerg       }
487330f729Sjoerg     }
497330f729Sjoerg   }
507330f729Sjoerg 
517330f729Sjoerg private:
527330f729Sjoerg   std::vector<std::unique_ptr<CompilerInstance>> CIs;
537330f729Sjoerg };
547330f729Sjoerg 
557330f729Sjoerg /// Members of ChainedIncludesSource, factored out so we can initialize
567330f729Sjoerg /// them before we initialize the ExternalSemaSource base class.
577330f729Sjoerg struct ChainedIncludesSourceMembers {
ChainedIncludesSourceMembers__anonc72e21680111::ChainedIncludesSourceMembers587330f729Sjoerg   ChainedIncludesSourceMembers(
597330f729Sjoerg       std::vector<std::unique_ptr<CompilerInstance>> CIs,
607330f729Sjoerg       IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
617330f729Sjoerg       : Impl(std::move(CIs)), FinalReader(std::move(FinalReader)) {}
627330f729Sjoerg   ChainedIncludesSourceImpl Impl;
637330f729Sjoerg   IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
647330f729Sjoerg };
657330f729Sjoerg 
667330f729Sjoerg /// Use MultiplexExternalSemaSource to dispatch all ExternalSemaSource
677330f729Sjoerg /// calls to the final reader.
687330f729Sjoerg class ChainedIncludesSource
697330f729Sjoerg     : private ChainedIncludesSourceMembers,
707330f729Sjoerg       public MultiplexExternalSemaSource {
717330f729Sjoerg public:
ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)727330f729Sjoerg   ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,
737330f729Sjoerg                         IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
747330f729Sjoerg       : ChainedIncludesSourceMembers(std::move(CIs), std::move(FinalReader)),
757330f729Sjoerg         MultiplexExternalSemaSource(Impl, *this->FinalReader) {}
767330f729Sjoerg };
777330f729Sjoerg }
787330f729Sjoerg 
797330f729Sjoerg static ASTReader *
createASTReader(CompilerInstance & CI,StringRef pchFile,SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> & MemBufs,SmallVectorImpl<std::string> & bufNames,ASTDeserializationListener * deserialListener=nullptr)807330f729Sjoerg createASTReader(CompilerInstance &CI, StringRef pchFile,
817330f729Sjoerg                 SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
827330f729Sjoerg                 SmallVectorImpl<std::string> &bufNames,
837330f729Sjoerg                 ASTDeserializationListener *deserialListener = nullptr) {
847330f729Sjoerg   Preprocessor &PP = CI.getPreprocessor();
857330f729Sjoerg   std::unique_ptr<ASTReader> Reader;
86*e038c9c4Sjoerg   Reader.reset(new ASTReader(
87*e038c9c4Sjoerg       PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(),
887330f729Sjoerg       /*Extensions=*/{},
89*e038c9c4Sjoerg       /*isysroot=*/"", DisableValidationForModuleKind::PCH));
907330f729Sjoerg   for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
917330f729Sjoerg     StringRef sr(bufNames[ti]);
927330f729Sjoerg     Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
937330f729Sjoerg   }
947330f729Sjoerg   Reader->setDeserializationListener(deserialListener);
957330f729Sjoerg   switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
967330f729Sjoerg                           ASTReader::ARR_None)) {
977330f729Sjoerg   case ASTReader::Success:
987330f729Sjoerg     // Set the predefines buffer as suggested by the PCH reader.
997330f729Sjoerg     PP.setPredefines(Reader->getSuggestedPredefines());
1007330f729Sjoerg     return Reader.release();
1017330f729Sjoerg 
1027330f729Sjoerg   case ASTReader::Failure:
1037330f729Sjoerg   case ASTReader::Missing:
1047330f729Sjoerg   case ASTReader::OutOfDate:
1057330f729Sjoerg   case ASTReader::VersionMismatch:
1067330f729Sjoerg   case ASTReader::ConfigurationMismatch:
1077330f729Sjoerg   case ASTReader::HadErrors:
1087330f729Sjoerg     break;
1097330f729Sjoerg   }
1107330f729Sjoerg   return nullptr;
1117330f729Sjoerg }
1127330f729Sjoerg 
createChainedIncludesSource(CompilerInstance & CI,IntrusiveRefCntPtr<ExternalSemaSource> & Reader)1137330f729Sjoerg IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
1147330f729Sjoerg     CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
1157330f729Sjoerg 
1167330f729Sjoerg   std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
1177330f729Sjoerg   assert(!includes.empty() && "No '-chain-include' in options!");
1187330f729Sjoerg 
1197330f729Sjoerg   std::vector<std::unique_ptr<CompilerInstance>> CIs;
1207330f729Sjoerg   InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
1217330f729Sjoerg 
1227330f729Sjoerg   SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
1237330f729Sjoerg   SmallVector<std::string, 4> serialBufNames;
1247330f729Sjoerg 
1257330f729Sjoerg   for (unsigned i = 0, e = includes.size(); i != e; ++i) {
1267330f729Sjoerg     bool firstInclude = (i == 0);
1277330f729Sjoerg     std::unique_ptr<CompilerInvocation> CInvok;
1287330f729Sjoerg     CInvok.reset(new CompilerInvocation(CI.getInvocation()));
1297330f729Sjoerg 
1307330f729Sjoerg     CInvok->getPreprocessorOpts().ChainedIncludes.clear();
1317330f729Sjoerg     CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
132*e038c9c4Sjoerg     CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =
133*e038c9c4Sjoerg         DisableValidationForModuleKind::PCH;
1347330f729Sjoerg     CInvok->getPreprocessorOpts().Includes.clear();
1357330f729Sjoerg     CInvok->getPreprocessorOpts().MacroIncludes.clear();
1367330f729Sjoerg     CInvok->getPreprocessorOpts().Macros.clear();
1377330f729Sjoerg 
1387330f729Sjoerg     CInvok->getFrontendOpts().Inputs.clear();
1397330f729Sjoerg     FrontendInputFile InputFile(includes[i], IK);
1407330f729Sjoerg     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
1417330f729Sjoerg 
1427330f729Sjoerg     TextDiagnosticPrinter *DiagClient =
1437330f729Sjoerg       new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
1447330f729Sjoerg     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
1457330f729Sjoerg     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
1467330f729Sjoerg         new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
1477330f729Sjoerg 
1487330f729Sjoerg     std::unique_ptr<CompilerInstance> Clang(
1497330f729Sjoerg         new CompilerInstance(CI.getPCHContainerOperations()));
1507330f729Sjoerg     Clang->setInvocation(std::move(CInvok));
1517330f729Sjoerg     Clang->setDiagnostics(Diags.get());
1527330f729Sjoerg     Clang->setTarget(TargetInfo::CreateTargetInfo(
1537330f729Sjoerg         Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
1547330f729Sjoerg     Clang->createFileManager();
1557330f729Sjoerg     Clang->createSourceManager(Clang->getFileManager());
1567330f729Sjoerg     Clang->createPreprocessor(TU_Prefix);
1577330f729Sjoerg     Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
1587330f729Sjoerg                                                  &Clang->getPreprocessor());
1597330f729Sjoerg     Clang->createASTContext();
1607330f729Sjoerg 
1617330f729Sjoerg     auto Buffer = std::make_shared<PCHBuffer>();
1627330f729Sjoerg     ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;
1637330f729Sjoerg     auto consumer = std::make_unique<PCHGenerator>(
1647330f729Sjoerg         Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
1657330f729Sjoerg         Buffer, Extensions, /*AllowASTWithErrors=*/true);
1667330f729Sjoerg     Clang->getASTContext().setASTMutationListener(
1677330f729Sjoerg                                             consumer->GetASTMutationListener());
1687330f729Sjoerg     Clang->setASTConsumer(std::move(consumer));
1697330f729Sjoerg     Clang->createSema(TU_Prefix, nullptr);
1707330f729Sjoerg 
1717330f729Sjoerg     if (firstInclude) {
1727330f729Sjoerg       Preprocessor &PP = Clang->getPreprocessor();
1737330f729Sjoerg       PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
1747330f729Sjoerg                                              PP.getLangOpts());
1757330f729Sjoerg     } else {
1767330f729Sjoerg       assert(!SerialBufs.empty());
1777330f729Sjoerg       SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
1787330f729Sjoerg       // TODO: Pass through the existing MemoryBuffer instances instead of
1797330f729Sjoerg       // allocating new ones.
1807330f729Sjoerg       for (auto &SB : SerialBufs)
1817330f729Sjoerg         Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
1827330f729Sjoerg       std::string pchName = includes[i-1];
1837330f729Sjoerg       llvm::raw_string_ostream os(pchName);
1847330f729Sjoerg       os << ".pch" << i-1;
1857330f729Sjoerg       serialBufNames.push_back(os.str());
1867330f729Sjoerg 
1877330f729Sjoerg       IntrusiveRefCntPtr<ASTReader> Reader;
1887330f729Sjoerg       Reader = createASTReader(
1897330f729Sjoerg           *Clang, pchName, Bufs, serialBufNames,
1907330f729Sjoerg           Clang->getASTConsumer().GetASTDeserializationListener());
1917330f729Sjoerg       if (!Reader)
1927330f729Sjoerg         return nullptr;
193*e038c9c4Sjoerg       Clang->setASTReader(Reader);
1947330f729Sjoerg       Clang->getASTContext().setExternalSource(Reader);
1957330f729Sjoerg     }
1967330f729Sjoerg 
1977330f729Sjoerg     if (!Clang->InitializeSourceManager(InputFile))
1987330f729Sjoerg       return nullptr;
1997330f729Sjoerg 
2007330f729Sjoerg     ParseAST(Clang->getSema());
2017330f729Sjoerg     Clang->getDiagnosticClient().EndSourceFile();
2027330f729Sjoerg     assert(Buffer->IsComplete && "serialization did not complete");
2037330f729Sjoerg     auto &serialAST = Buffer->Data;
2047330f729Sjoerg     SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
2057330f729Sjoerg         StringRef(serialAST.data(), serialAST.size())));
2067330f729Sjoerg     serialAST.clear();
2077330f729Sjoerg     CIs.push_back(std::move(Clang));
2087330f729Sjoerg   }
2097330f729Sjoerg 
2107330f729Sjoerg   assert(!SerialBufs.empty());
2117330f729Sjoerg   std::string pchName = includes.back() + ".pch-final";
2127330f729Sjoerg   serialBufNames.push_back(pchName);
2137330f729Sjoerg   Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
2147330f729Sjoerg   if (!Reader)
2157330f729Sjoerg     return nullptr;
2167330f729Sjoerg 
2177330f729Sjoerg   return IntrusiveRefCntPtr<ChainedIncludesSource>(
2187330f729Sjoerg       new ChainedIncludesSource(std::move(CIs), Reader));
2197330f729Sjoerg }
220