brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · 049277c Raw
200 lines · cpp
1//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  This file defines the ChainedIncludesSource class, which converts headers10//  to chained PCHs in memory, mainly used for testing.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Basic/Builtins.h"15#include "clang/Basic/TargetInfo.h"16#include "clang/Frontend/ASTUnit.h"17#include "clang/Frontend/CompilerInstance.h"18#include "clang/Frontend/TextDiagnosticPrinter.h"19#include "clang/Lex/Preprocessor.h"20#include "clang/Lex/PreprocessorOptions.h"21#include "clang/Parse/ParseAST.h"22#include "clang/Sema/MultiplexExternalSemaSource.h"23#include "clang/Serialization/ASTReader.h"24#include "clang/Serialization/ASTWriter.h"25#include "llvm/Support/MemoryBuffer.h"26 27using namespace clang;28 29namespace {30class ChainedIncludesSource : public ExternalSemaSource {31public:32  ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)33      : CIs(std::move(CIs)) {}34 35protected:36  //===--------------------------------------------------------------------===//37  // ExternalASTSource interface.38  //===--------------------------------------------------------------------===//39 40  /// Return the amount of memory used by memory buffers, breaking down41  /// by heap-backed versus mmap'ed memory.42  void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {43    for (unsigned i = 0, e = CIs.size(); i != e; ++i) {44      if (const ExternalASTSource *eSrc =45          CIs[i]->getASTContext().getExternalSource()) {46        eSrc->getMemoryBufferSizes(sizes);47      }48    }49  }50 51private:52  std::vector<std::unique_ptr<CompilerInstance>> CIs;53};54} // end anonymous namespace55 56static llvm::IntrusiveRefCntPtr<ASTReader>57createASTReader(CompilerInstance &CI, StringRef pchFile,58                SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,59                SmallVectorImpl<std::string> &bufNames,60                ASTDeserializationListener *deserialListener = nullptr) {61  Preprocessor &PP = CI.getPreprocessor();62  auto Reader = llvm::makeIntrusiveRefCnt<ASTReader>(63      PP, CI.getModuleCache(), &CI.getASTContext(), CI.getPCHContainerReader(),64      CI.getCodeGenOpts(),65      /*Extensions=*/ArrayRef<std::shared_ptr<ModuleFileExtension>>(),66      /*isysroot=*/"", DisableValidationForModuleKind::PCH);67  for (unsigned ti = 0; ti < bufNames.size(); ++ti) {68    StringRef sr(bufNames[ti]);69    Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));70  }71  Reader->setDeserializationListener(deserialListener);72  switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),73                          ASTReader::ARR_None)) {74  case ASTReader::Success:75    // Set the predefines buffer as suggested by the PCH reader.76    PP.setPredefines(Reader->getSuggestedPredefines());77    return Reader;78 79  case ASTReader::Failure:80  case ASTReader::Missing:81  case ASTReader::OutOfDate:82  case ASTReader::VersionMismatch:83  case ASTReader::ConfigurationMismatch:84  case ASTReader::HadErrors:85    break;86  }87  return nullptr;88}89 90IntrusiveRefCntPtr<ExternalSemaSource>91clang::createChainedIncludesSource(CompilerInstance &CI,92                                   IntrusiveRefCntPtr<ASTReader> &OutReader) {93 94  std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;95  assert(!includes.empty() && "No '-chain-include' in options!");96 97  std::vector<std::unique_ptr<CompilerInstance>> CIs;98  InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();99 100  SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;101  SmallVector<std::string, 4> serialBufNames;102 103  for (unsigned i = 0, e = includes.size(); i != e; ++i) {104    bool firstInclude = (i == 0);105    std::unique_ptr<CompilerInvocation> CInvok;106    CInvok.reset(new CompilerInvocation(CI.getInvocation()));107 108    CInvok->getPreprocessorOpts().ChainedIncludes.clear();109    CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();110    CInvok->getPreprocessorOpts().DisablePCHOrModuleValidation =111        DisableValidationForModuleKind::PCH;112    CInvok->getPreprocessorOpts().Includes.clear();113    CInvok->getPreprocessorOpts().MacroIncludes.clear();114    CInvok->getPreprocessorOpts().Macros.clear();115 116    CInvok->getFrontendOpts().Inputs.clear();117    FrontendInputFile InputFile(includes[i], IK);118    CInvok->getFrontendOpts().Inputs.push_back(InputFile);119 120    TextDiagnosticPrinter *DiagClient =121        new TextDiagnosticPrinter(llvm::errs(), CI.getDiagnosticOpts());122    auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(123        DiagnosticIDs::create(), CI.getDiagnosticOpts(), DiagClient);124 125    auto Clang = std::make_unique<CompilerInstance>(126        std::move(CInvok), CI.getPCHContainerOperations());127    Clang->createVirtualFileSystem();128    Clang->setDiagnostics(Diags);129    Clang->setTarget(TargetInfo::CreateTargetInfo(130        Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));131    Clang->createFileManager();132    Clang->createSourceManager();133    Clang->createPreprocessor(TU_Prefix);134    Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),135                                                 &Clang->getPreprocessor());136    Clang->createASTContext();137 138    auto Buffer = std::make_shared<PCHBuffer>();139    ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;140    auto consumer = std::make_unique<PCHGenerator>(141        Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",142        Buffer, Clang->getCodeGenOpts(), Extensions,143        /*AllowASTWithErrors=*/true);144    Clang->getASTContext().setASTMutationListener(145                                            consumer->GetASTMutationListener());146    Clang->setASTConsumer(std::move(consumer));147    Clang->createSema(TU_Prefix, nullptr);148 149    if (firstInclude) {150      Preprocessor &PP = Clang->getPreprocessor();151      PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),152                                             PP.getLangOpts());153    } else {154      assert(!SerialBufs.empty());155      SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;156      // TODO: Pass through the existing MemoryBuffer instances instead of157      // allocating new ones.158      for (auto &SB : SerialBufs)159        Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));160      std::string pchName = includes[i-1];161      llvm::raw_string_ostream os(pchName);162      os << ".pch" << i-1;163      serialBufNames.push_back(pchName);164 165      IntrusiveRefCntPtr<ASTReader> Reader;166      Reader = createASTReader(167          *Clang, pchName, Bufs, serialBufNames,168          Clang->getASTConsumer().GetASTDeserializationListener());169      if (!Reader)170        return nullptr;171      Clang->setASTReader(Reader);172      Clang->getASTContext().setExternalSource(Reader);173    }174 175    if (!Clang->InitializeSourceManager(InputFile))176      return nullptr;177 178    ParseAST(Clang->getSema());179    Clang->getDiagnosticClient().EndSourceFile();180    assert(Buffer->IsComplete && "serialization did not complete");181    auto &serialAST = Buffer->Data;182    SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(183        StringRef(serialAST.data(), serialAST.size())));184    serialAST.clear();185    CIs.push_back(std::move(Clang));186  }187 188  assert(!SerialBufs.empty());189  std::string pchName = includes.back() + ".pch-final";190  serialBufNames.push_back(pchName);191  OutReader = createASTReader(CI, pchName, SerialBufs, serialBufNames);192  if (!OutReader)193    return nullptr;194 195  auto ChainedSrc =196      llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs));197  return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(198      std::move(ChainedSrc), OutReader);199}200