Home | History | Annotate | Download | only in Frontend
      1 //===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defines the ChainedIncludesSource class, which converts headers
     11 //  to chained PCHs in memory, mainly used for testing.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     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/Parse/ParseAST.h"
     21 #include "clang/Serialization/ASTReader.h"
     22 #include "clang/Serialization/ASTWriter.h"
     23 #include "llvm/Support/MemoryBuffer.h"
     24 
     25 using namespace clang;
     26 
     27 namespace {
     28 class ChainedIncludesSource : public ExternalSemaSource {
     29 public:
     30   ~ChainedIncludesSource() override;
     31 
     32   ExternalSemaSource &getFinalReader() const { return *FinalReader; }
     33 
     34   std::vector<CompilerInstance *> CIs;
     35   IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
     36 
     37 protected:
     38   //===----------------------------------------------------------------------===//
     39   // ExternalASTSource interface.
     40   //===----------------------------------------------------------------------===//
     41 
     42   Decl *GetExternalDecl(uint32_t ID) override;
     43   Selector GetExternalSelector(uint32_t ID) override;
     44   uint32_t GetNumExternalSelectors() override;
     45   Stmt *GetExternalDeclStmt(uint64_t Offset) override;
     46   CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
     47   CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
     48   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
     49                                       DeclarationName Name) override;
     50   void
     51   FindExternalLexicalDecls(const DeclContext *DC,
     52                            llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
     53                            SmallVectorImpl<Decl *> &Result) override;
     54   void CompleteType(TagDecl *Tag) override;
     55   void CompleteType(ObjCInterfaceDecl *Class) override;
     56   void StartedDeserializing() override;
     57   void FinishedDeserializing() override;
     58   void StartTranslationUnit(ASTConsumer *Consumer) override;
     59   void PrintStats() override;
     60 
     61   /// Return the amount of memory used by memory buffers, breaking down
     62   /// by heap-backed versus mmap'ed memory.
     63   void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override;
     64 
     65   //===----------------------------------------------------------------------===//
     66   // ExternalSemaSource interface.
     67   //===----------------------------------------------------------------------===//
     68 
     69   void InitializeSema(Sema &S) override;
     70   void ForgetSema() override;
     71   void ReadMethodPool(Selector Sel) override;
     72   bool LookupUnqualified(LookupResult &R, Scope *S) override;
     73 };
     74 }
     75 
     76 static ASTReader *
     77 createASTReader(CompilerInstance &CI, StringRef pchFile,
     78                 SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>> &MemBufs,
     79                 SmallVectorImpl<std::string> &bufNames,
     80                 ASTDeserializationListener *deserialListener = nullptr) {
     81   Preprocessor &PP = CI.getPreprocessor();
     82   std::unique_ptr<ASTReader> Reader;
     83   Reader.reset(new ASTReader(PP, CI.getASTContext(),
     84                              CI.getPCHContainerReader(),
     85                              /*Extensions=*/{ },
     86                              /*isysroot=*/"", /*DisableValidation=*/true));
     87   for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
     88     StringRef sr(bufNames[ti]);
     89     Reader->addInMemoryBuffer(sr, std::move(MemBufs[ti]));
     90   }
     91   Reader->setDeserializationListener(deserialListener);
     92   switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
     93                           ASTReader::ARR_None)) {
     94   case ASTReader::Success:
     95     // Set the predefines buffer as suggested by the PCH reader.
     96     PP.setPredefines(Reader->getSuggestedPredefines());
     97     return Reader.release();
     98 
     99   case ASTReader::Failure:
    100   case ASTReader::Missing:
    101   case ASTReader::OutOfDate:
    102   case ASTReader::VersionMismatch:
    103   case ASTReader::ConfigurationMismatch:
    104   case ASTReader::HadErrors:
    105     break;
    106   }
    107   return nullptr;
    108 }
    109 
    110 ChainedIncludesSource::~ChainedIncludesSource() {
    111   for (unsigned i = 0, e = CIs.size(); i != e; ++i)
    112     delete CIs[i];
    113 }
    114 
    115 IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
    116     CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
    117 
    118   std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
    119   assert(!includes.empty() && "No '-chain-include' in options!");
    120 
    121   IntrusiveRefCntPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
    122   InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
    123 
    124   SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> SerialBufs;
    125   SmallVector<std::string, 4> serialBufNames;
    126 
    127   for (unsigned i = 0, e = includes.size(); i != e; ++i) {
    128     bool firstInclude = (i == 0);
    129     std::unique_ptr<CompilerInvocation> CInvok;
    130     CInvok.reset(new CompilerInvocation(CI.getInvocation()));
    131 
    132     CInvok->getPreprocessorOpts().ChainedIncludes.clear();
    133     CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear();
    134     CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
    135     CInvok->getPreprocessorOpts().DisablePCHValidation = true;
    136     CInvok->getPreprocessorOpts().Includes.clear();
    137     CInvok->getPreprocessorOpts().MacroIncludes.clear();
    138     CInvok->getPreprocessorOpts().Macros.clear();
    139 
    140     CInvok->getFrontendOpts().Inputs.clear();
    141     FrontendInputFile InputFile(includes[i], IK);
    142     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
    143 
    144     TextDiagnosticPrinter *DiagClient =
    145       new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
    146     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    147     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    148         new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
    149 
    150     std::unique_ptr<CompilerInstance> Clang(
    151         new CompilerInstance(CI.getPCHContainerOperations()));
    152     Clang->setInvocation(CInvok.release());
    153     Clang->setDiagnostics(Diags.get());
    154     Clang->setTarget(TargetInfo::CreateTargetInfo(
    155         Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
    156     Clang->createFileManager();
    157     Clang->createSourceManager(Clang->getFileManager());
    158     Clang->createPreprocessor(TU_Prefix);
    159     Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
    160                                                  &Clang->getPreprocessor());
    161     Clang->createASTContext();
    162 
    163     auto Buffer = std::make_shared<PCHBuffer>();
    164     ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions;
    165     auto consumer = llvm::make_unique<PCHGenerator>(
    166         Clang->getPreprocessor(), "-", nullptr, /*isysroot=*/"", Buffer,
    167         Extensions, /*AllowASTWithErrors=*/true);
    168     Clang->getASTContext().setASTMutationListener(
    169                                             consumer->GetASTMutationListener());
    170     Clang->setASTConsumer(std::move(consumer));
    171     Clang->createSema(TU_Prefix, nullptr);
    172 
    173     if (firstInclude) {
    174       Preprocessor &PP = Clang->getPreprocessor();
    175       PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
    176                                              PP.getLangOpts());
    177     } else {
    178       assert(!SerialBufs.empty());
    179       SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4> Bufs;
    180       // TODO: Pass through the existing MemoryBuffer instances instead of
    181       // allocating new ones.
    182       for (auto &SB : SerialBufs)
    183         Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
    184       std::string pchName = includes[i-1];
    185       llvm::raw_string_ostream os(pchName);
    186       os << ".pch" << i-1;
    187       serialBufNames.push_back(os.str());
    188 
    189       IntrusiveRefCntPtr<ASTReader> Reader;
    190       Reader = createASTReader(
    191           *Clang, pchName, Bufs, serialBufNames,
    192           Clang->getASTConsumer().GetASTDeserializationListener());
    193       if (!Reader)
    194         return nullptr;
    195       Clang->setModuleManager(Reader);
    196       Clang->getASTContext().setExternalSource(Reader);
    197     }
    198 
    199     if (!Clang->InitializeSourceManager(InputFile))
    200       return nullptr;
    201 
    202     ParseAST(Clang->getSema());
    203     Clang->getDiagnosticClient().EndSourceFile();
    204     assert(Buffer->IsComplete && "serialization did not complete");
    205     auto &serialAST = Buffer->Data;
    206     SerialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
    207         StringRef(serialAST.data(), serialAST.size())));
    208     serialAST.clear();
    209     source->CIs.push_back(Clang.release());
    210   }
    211 
    212   assert(!SerialBufs.empty());
    213   std::string pchName = includes.back() + ".pch-final";
    214   serialBufNames.push_back(pchName);
    215   Reader = createASTReader(CI, pchName, SerialBufs, serialBufNames);
    216   if (!Reader)
    217     return nullptr;
    218 
    219   source->FinalReader = Reader;
    220   return source;
    221 }
    222 
    223 //===----------------------------------------------------------------------===//
    224 // ExternalASTSource interface.
    225 //===----------------------------------------------------------------------===//
    226 
    227 Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) {
    228   return getFinalReader().GetExternalDecl(ID);
    229 }
    230 Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) {
    231   return getFinalReader().GetExternalSelector(ID);
    232 }
    233 uint32_t ChainedIncludesSource::GetNumExternalSelectors() {
    234   return getFinalReader().GetNumExternalSelectors();
    235 }
    236 Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) {
    237   return getFinalReader().GetExternalDeclStmt(Offset);
    238 }
    239 CXXBaseSpecifier *
    240 ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
    241   return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
    242 }
    243 CXXCtorInitializer **
    244 ChainedIncludesSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
    245   return getFinalReader().GetExternalCXXCtorInitializers(Offset);
    246 }
    247 bool
    248 ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
    249                                                       DeclarationName Name) {
    250   return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
    251 }
    252 void ChainedIncludesSource::FindExternalLexicalDecls(
    253     const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
    254     SmallVectorImpl<Decl *> &Result) {
    255   return getFinalReader().FindExternalLexicalDecls(DC, IsKindWeWant, Result);
    256 }
    257 void ChainedIncludesSource::CompleteType(TagDecl *Tag) {
    258   return getFinalReader().CompleteType(Tag);
    259 }
    260 void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) {
    261   return getFinalReader().CompleteType(Class);
    262 }
    263 void ChainedIncludesSource::StartedDeserializing() {
    264   return getFinalReader().StartedDeserializing();
    265 }
    266 void ChainedIncludesSource::FinishedDeserializing() {
    267   return getFinalReader().FinishedDeserializing();
    268 }
    269 void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) {
    270   return getFinalReader().StartTranslationUnit(Consumer);
    271 }
    272 void ChainedIncludesSource::PrintStats() {
    273   return getFinalReader().PrintStats();
    274 }
    275 void ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{
    276   for (unsigned i = 0, e = CIs.size(); i != e; ++i) {
    277     if (const ExternalASTSource *eSrc =
    278         CIs[i]->getASTContext().getExternalSource()) {
    279       eSrc->getMemoryBufferSizes(sizes);
    280     }
    281   }
    282 
    283   getFinalReader().getMemoryBufferSizes(sizes);
    284 }
    285 
    286 void ChainedIncludesSource::InitializeSema(Sema &S) {
    287   return getFinalReader().InitializeSema(S);
    288 }
    289 void ChainedIncludesSource::ForgetSema() {
    290   return getFinalReader().ForgetSema();
    291 }
    292 void ChainedIncludesSource::ReadMethodPool(Selector Sel) {
    293   getFinalReader().ReadMethodPool(Sel);
    294 }
    295 bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) {
    296   return getFinalReader().LookupUnqualified(R, S);
    297 }
    298 
    299