xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/ChainedIncludesSource.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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