10b57cec5SDimitry Andric //===--- GeneratePCH.cpp - Sema Consumer for PCH Generation -----*- 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 PCHGenerator, which as a SemaConsumer that generates
100b57cec5SDimitry Andric //  a PCH file.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
150b57cec5SDimitry Andric #include "clang/Lex/HeaderSearch.h"
160b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
170b57cec5SDimitry Andric #include "clang/Sema/SemaConsumer.h"
180b57cec5SDimitry Andric #include "clang/Serialization/ASTWriter.h"
190b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace clang;
220b57cec5SDimitry Andric 
PCHGenerator(const Preprocessor & PP,InMemoryModuleCache & ModuleCache,StringRef OutputFile,StringRef isysroot,std::shared_ptr<PCHBuffer> Buffer,ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,bool AllowASTWithErrors,bool IncludeTimestamps,bool BuildingImplicitModule,bool ShouldCacheASTInMemory)230b57cec5SDimitry Andric PCHGenerator::PCHGenerator(
240b57cec5SDimitry Andric     const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
250b57cec5SDimitry Andric     StringRef OutputFile, StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer,
260b57cec5SDimitry Andric     ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
270b57cec5SDimitry Andric     bool AllowASTWithErrors, bool IncludeTimestamps,
285f757f3fSDimitry Andric     bool BuildingImplicitModule, bool ShouldCacheASTInMemory)
290b57cec5SDimitry Andric     : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()),
300b57cec5SDimitry Andric       SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data),
310b57cec5SDimitry Andric       Writer(Stream, this->Buffer->Data, ModuleCache, Extensions,
325f757f3fSDimitry Andric              IncludeTimestamps, BuildingImplicitModule),
330b57cec5SDimitry Andric       AllowASTWithErrors(AllowASTWithErrors),
340b57cec5SDimitry Andric       ShouldCacheASTInMemory(ShouldCacheASTInMemory) {
350b57cec5SDimitry Andric   this->Buffer->IsComplete = false;
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
~PCHGenerator()380b57cec5SDimitry Andric PCHGenerator::~PCHGenerator() {
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
HandleTranslationUnit(ASTContext & Ctx)410b57cec5SDimitry Andric void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
420b57cec5SDimitry Andric   // Don't create a PCH if there were fatal failures during module loading.
430b57cec5SDimitry Andric   if (PP.getModuleLoader().HadFatalFailure)
440b57cec5SDimitry Andric     return;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   bool hasErrors = PP.getDiagnostics().hasErrorOccurred();
470b57cec5SDimitry Andric   if (hasErrors && !AllowASTWithErrors)
480b57cec5SDimitry Andric     return;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   Module *Module = nullptr;
510b57cec5SDimitry Andric   if (PP.getLangOpts().isCompilingModule()) {
520b57cec5SDimitry Andric     Module = PP.getHeaderSearchInfo().lookupModule(
53349cc55cSDimitry Andric         PP.getLangOpts().CurrentModule, SourceLocation(),
54349cc55cSDimitry Andric         /*AllowSearch*/ false);
550b57cec5SDimitry Andric     if (!Module) {
560b57cec5SDimitry Andric       assert(hasErrors && "emitting module but current module doesn't exist");
570b57cec5SDimitry Andric       return;
580b57cec5SDimitry Andric     }
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
615ffd83dbSDimitry Andric   // Errors that do not prevent the PCH from being written should not cause the
625ffd83dbSDimitry Andric   // overall compilation to fail either.
635ffd83dbSDimitry Andric   if (AllowASTWithErrors)
645ffd83dbSDimitry Andric     PP.getDiagnostics().getClient()->clear();
655ffd83dbSDimitry Andric 
660b57cec5SDimitry Andric   // Emit the PCH file to the Buffer.
670b57cec5SDimitry Andric   assert(SemaPtr && "No Sema?");
685f757f3fSDimitry Andric   Buffer->Signature = Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot,
690b57cec5SDimitry Andric                                       ShouldCacheASTInMemory);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   Buffer->IsComplete = true;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
GetASTMutationListener()740b57cec5SDimitry Andric ASTMutationListener *PCHGenerator::GetASTMutationListener() {
750b57cec5SDimitry Andric   return &Writer;
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
GetASTDeserializationListener()780b57cec5SDimitry Andric ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
790b57cec5SDimitry Andric   return &Writer;
800b57cec5SDimitry Andric }
81