xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Frontend/FrontendActions.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- FrontendActions.cpp ----------------------------------------------===//
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 #include "clang/Frontend/FrontendActions.h"
107330f729Sjoerg #include "clang/AST/ASTConsumer.h"
117330f729Sjoerg #include "clang/Basic/FileManager.h"
12*e038c9c4Sjoerg #include "clang/Basic/TargetInfo.h"
137330f729Sjoerg #include "clang/Basic/LangStandard.h"
147330f729Sjoerg #include "clang/Frontend/ASTConsumers.h"
157330f729Sjoerg #include "clang/Frontend/CompilerInstance.h"
167330f729Sjoerg #include "clang/Frontend/FrontendDiagnostic.h"
177330f729Sjoerg #include "clang/Frontend/MultiplexConsumer.h"
187330f729Sjoerg #include "clang/Frontend/Utils.h"
197330f729Sjoerg #include "clang/Lex/DependencyDirectivesSourceMinimizer.h"
207330f729Sjoerg #include "clang/Lex/HeaderSearch.h"
217330f729Sjoerg #include "clang/Lex/Preprocessor.h"
227330f729Sjoerg #include "clang/Lex/PreprocessorOptions.h"
237330f729Sjoerg #include "clang/Sema/TemplateInstCallback.h"
247330f729Sjoerg #include "clang/Serialization/ASTReader.h"
257330f729Sjoerg #include "clang/Serialization/ASTWriter.h"
267330f729Sjoerg #include "llvm/Support/FileSystem.h"
277330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
287330f729Sjoerg #include "llvm/Support/Path.h"
297330f729Sjoerg #include "llvm/Support/YAMLTraits.h"
307330f729Sjoerg #include "llvm/Support/raw_ostream.h"
317330f729Sjoerg #include <memory>
327330f729Sjoerg #include <system_error>
337330f729Sjoerg 
347330f729Sjoerg using namespace clang;
357330f729Sjoerg 
367330f729Sjoerg namespace {
GetCodeCompletionConsumer(CompilerInstance & CI)377330f729Sjoerg CodeCompleteConsumer *GetCodeCompletionConsumer(CompilerInstance &CI) {
387330f729Sjoerg   return CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer()
397330f729Sjoerg                                         : nullptr;
407330f729Sjoerg }
417330f729Sjoerg 
EnsureSemaIsCreated(CompilerInstance & CI,FrontendAction & Action)427330f729Sjoerg void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) {
437330f729Sjoerg   if (Action.hasCodeCompletionSupport() &&
447330f729Sjoerg       !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
457330f729Sjoerg     CI.createCodeCompletionConsumer();
467330f729Sjoerg 
477330f729Sjoerg   if (!CI.hasSema())
487330f729Sjoerg     CI.createSema(Action.getTranslationUnitKind(),
497330f729Sjoerg                   GetCodeCompletionConsumer(CI));
507330f729Sjoerg }
517330f729Sjoerg } // namespace
527330f729Sjoerg 
537330f729Sjoerg //===----------------------------------------------------------------------===//
547330f729Sjoerg // Custom Actions
557330f729Sjoerg //===----------------------------------------------------------------------===//
567330f729Sjoerg 
577330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)587330f729Sjoerg InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
597330f729Sjoerg   return std::make_unique<ASTConsumer>();
607330f729Sjoerg }
617330f729Sjoerg 
ExecuteAction()627330f729Sjoerg void InitOnlyAction::ExecuteAction() {
637330f729Sjoerg }
647330f729Sjoerg 
657330f729Sjoerg //===----------------------------------------------------------------------===//
667330f729Sjoerg // AST Consumer Actions
677330f729Sjoerg //===----------------------------------------------------------------------===//
687330f729Sjoerg 
697330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)707330f729Sjoerg ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
717330f729Sjoerg   if (std::unique_ptr<raw_ostream> OS =
727330f729Sjoerg           CI.createDefaultOutputFile(false, InFile))
737330f729Sjoerg     return CreateASTPrinter(std::move(OS), CI.getFrontendOpts().ASTDumpFilter);
747330f729Sjoerg   return nullptr;
757330f729Sjoerg }
767330f729Sjoerg 
777330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)787330f729Sjoerg ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
797330f729Sjoerg   const FrontendOptions &Opts = CI.getFrontendOpts();
807330f729Sjoerg   return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter,
817330f729Sjoerg                          Opts.ASTDumpDecls, Opts.ASTDumpAll,
82*e038c9c4Sjoerg                          Opts.ASTDumpLookups, Opts.ASTDumpDeclTypes,
83*e038c9c4Sjoerg                          Opts.ASTDumpFormat);
847330f729Sjoerg }
857330f729Sjoerg 
867330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)877330f729Sjoerg ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
887330f729Sjoerg   return CreateASTDeclNodeLister();
897330f729Sjoerg }
907330f729Sjoerg 
917330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)927330f729Sjoerg ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
937330f729Sjoerg   return CreateASTViewer();
947330f729Sjoerg }
957330f729Sjoerg 
967330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)977330f729Sjoerg GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
987330f729Sjoerg   std::string Sysroot;
997330f729Sjoerg   if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot))
1007330f729Sjoerg     return nullptr;
1017330f729Sjoerg 
1027330f729Sjoerg   std::string OutputFile;
1037330f729Sjoerg   std::unique_ptr<raw_pwrite_stream> OS =
1047330f729Sjoerg       CreateOutputFile(CI, InFile, /*ref*/ OutputFile);
1057330f729Sjoerg   if (!OS)
1067330f729Sjoerg     return nullptr;
1077330f729Sjoerg 
1087330f729Sjoerg   if (!CI.getFrontendOpts().RelocatablePCH)
1097330f729Sjoerg     Sysroot.clear();
1107330f729Sjoerg 
1117330f729Sjoerg   const auto &FrontendOpts = CI.getFrontendOpts();
1127330f729Sjoerg   auto Buffer = std::make_shared<PCHBuffer>();
1137330f729Sjoerg   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
1147330f729Sjoerg   Consumers.push_back(std::make_unique<PCHGenerator>(
1157330f729Sjoerg       CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
1167330f729Sjoerg       FrontendOpts.ModuleFileExtensions,
1177330f729Sjoerg       CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
1187330f729Sjoerg       FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH));
1197330f729Sjoerg   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
120*e038c9c4Sjoerg       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
1217330f729Sjoerg 
1227330f729Sjoerg   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
1237330f729Sjoerg }
1247330f729Sjoerg 
ComputeASTConsumerArguments(CompilerInstance & CI,std::string & Sysroot)1257330f729Sjoerg bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
1267330f729Sjoerg                                                     std::string &Sysroot) {
1277330f729Sjoerg   Sysroot = CI.getHeaderSearchOpts().Sysroot;
1287330f729Sjoerg   if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
1297330f729Sjoerg     CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot);
1307330f729Sjoerg     return false;
1317330f729Sjoerg   }
1327330f729Sjoerg 
1337330f729Sjoerg   return true;
1347330f729Sjoerg }
1357330f729Sjoerg 
1367330f729Sjoerg std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile,std::string & OutputFile)1377330f729Sjoerg GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile,
1387330f729Sjoerg                                     std::string &OutputFile) {
139*e038c9c4Sjoerg   // Because this is exposed via libclang we must disable RemoveFileOnSignal.
140*e038c9c4Sjoerg   std::unique_ptr<raw_pwrite_stream> OS = CI.createDefaultOutputFile(
141*e038c9c4Sjoerg       /*Binary=*/true, InFile, /*Extension=*/"", /*RemoveFileOnSignal=*/false);
1427330f729Sjoerg   if (!OS)
1437330f729Sjoerg     return nullptr;
1447330f729Sjoerg 
1457330f729Sjoerg   OutputFile = CI.getFrontendOpts().OutputFile;
1467330f729Sjoerg   return OS;
1477330f729Sjoerg }
1487330f729Sjoerg 
shouldEraseOutputFiles()1497330f729Sjoerg bool GeneratePCHAction::shouldEraseOutputFiles() {
1507330f729Sjoerg   if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
1517330f729Sjoerg     return false;
1527330f729Sjoerg   return ASTFrontendAction::shouldEraseOutputFiles();
1537330f729Sjoerg }
1547330f729Sjoerg 
BeginSourceFileAction(CompilerInstance & CI)1557330f729Sjoerg bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
1567330f729Sjoerg   CI.getLangOpts().CompilingPCH = true;
1577330f729Sjoerg   return true;
1587330f729Sjoerg }
1597330f729Sjoerg 
1607330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)1617330f729Sjoerg GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
1627330f729Sjoerg                                         StringRef InFile) {
1637330f729Sjoerg   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
1647330f729Sjoerg   if (!OS)
1657330f729Sjoerg     return nullptr;
1667330f729Sjoerg 
1677330f729Sjoerg   std::string OutputFile = CI.getFrontendOpts().OutputFile;
1687330f729Sjoerg   std::string Sysroot;
1697330f729Sjoerg 
1707330f729Sjoerg   auto Buffer = std::make_shared<PCHBuffer>();
1717330f729Sjoerg   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
1727330f729Sjoerg 
1737330f729Sjoerg   Consumers.push_back(std::make_unique<PCHGenerator>(
1747330f729Sjoerg       CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
1757330f729Sjoerg       CI.getFrontendOpts().ModuleFileExtensions,
176*e038c9c4Sjoerg       /*AllowASTWithErrors=*/
177*e038c9c4Sjoerg       +CI.getFrontendOpts().AllowPCMWithCompilerErrors,
1787330f729Sjoerg       /*IncludeTimestamps=*/
1797330f729Sjoerg       +CI.getFrontendOpts().BuildingImplicitModule,
1807330f729Sjoerg       /*ShouldCacheASTInMemory=*/
1817330f729Sjoerg       +CI.getFrontendOpts().BuildingImplicitModule));
1827330f729Sjoerg   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
183*e038c9c4Sjoerg       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
1847330f729Sjoerg   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
1857330f729Sjoerg }
1867330f729Sjoerg 
shouldEraseOutputFiles()187*e038c9c4Sjoerg bool GenerateModuleAction::shouldEraseOutputFiles() {
188*e038c9c4Sjoerg   return !getCompilerInstance().getFrontendOpts().AllowPCMWithCompilerErrors &&
189*e038c9c4Sjoerg          ASTFrontendAction::shouldEraseOutputFiles();
190*e038c9c4Sjoerg }
191*e038c9c4Sjoerg 
BeginSourceFileAction(CompilerInstance & CI)1927330f729Sjoerg bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
1937330f729Sjoerg     CompilerInstance &CI) {
1947330f729Sjoerg   if (!CI.getLangOpts().Modules) {
1957330f729Sjoerg     CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules);
1967330f729Sjoerg     return false;
1977330f729Sjoerg   }
1987330f729Sjoerg 
1997330f729Sjoerg   return GenerateModuleAction::BeginSourceFileAction(CI);
2007330f729Sjoerg }
2017330f729Sjoerg 
2027330f729Sjoerg std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)2037330f729Sjoerg GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
2047330f729Sjoerg                                                     StringRef InFile) {
2057330f729Sjoerg   // If no output file was provided, figure out where this module would go
2067330f729Sjoerg   // in the module cache.
2077330f729Sjoerg   if (CI.getFrontendOpts().OutputFile.empty()) {
2087330f729Sjoerg     StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
2097330f729Sjoerg     if (ModuleMapFile.empty())
2107330f729Sjoerg       ModuleMapFile = InFile;
2117330f729Sjoerg 
2127330f729Sjoerg     HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
2137330f729Sjoerg     CI.getFrontendOpts().OutputFile =
2147330f729Sjoerg         HS.getCachedModuleFileName(CI.getLangOpts().CurrentModule,
2157330f729Sjoerg                                    ModuleMapFile);
2167330f729Sjoerg   }
2177330f729Sjoerg 
218*e038c9c4Sjoerg   // Because this is exposed via libclang we must disable RemoveFileOnSignal.
219*e038c9c4Sjoerg   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, /*Extension=*/"",
220*e038c9c4Sjoerg                                     /*RemoveFileOnSignal=*/false,
2217330f729Sjoerg                                     /*CreateMissingDirectories=*/true);
2227330f729Sjoerg }
2237330f729Sjoerg 
BeginSourceFileAction(CompilerInstance & CI)2247330f729Sjoerg bool GenerateModuleInterfaceAction::BeginSourceFileAction(
2257330f729Sjoerg     CompilerInstance &CI) {
2267330f729Sjoerg   if (!CI.getLangOpts().ModulesTS && !CI.getLangOpts().CPlusPlusModules) {
2277330f729Sjoerg     CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
2287330f729Sjoerg     return false;
2297330f729Sjoerg   }
2307330f729Sjoerg 
2317330f729Sjoerg   CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
2327330f729Sjoerg 
2337330f729Sjoerg   return GenerateModuleAction::BeginSourceFileAction(CI);
2347330f729Sjoerg }
2357330f729Sjoerg 
2367330f729Sjoerg std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)2377330f729Sjoerg GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
2387330f729Sjoerg                                                 StringRef InFile) {
2397330f729Sjoerg   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
2407330f729Sjoerg }
2417330f729Sjoerg 
PrepareToExecuteAction(CompilerInstance & CI)2427330f729Sjoerg bool GenerateHeaderModuleAction::PrepareToExecuteAction(
2437330f729Sjoerg     CompilerInstance &CI) {
2447330f729Sjoerg   if (!CI.getLangOpts().Modules) {
2457330f729Sjoerg     CI.getDiagnostics().Report(diag::err_header_module_requires_modules);
2467330f729Sjoerg     return false;
2477330f729Sjoerg   }
2487330f729Sjoerg 
2497330f729Sjoerg   auto &Inputs = CI.getFrontendOpts().Inputs;
2507330f729Sjoerg   if (Inputs.empty())
2517330f729Sjoerg     return GenerateModuleAction::BeginInvocation(CI);
2527330f729Sjoerg 
2537330f729Sjoerg   auto Kind = Inputs[0].getKind();
2547330f729Sjoerg 
2557330f729Sjoerg   // Convert the header file inputs into a single module input buffer.
2567330f729Sjoerg   SmallString<256> HeaderContents;
2577330f729Sjoerg   ModuleHeaders.reserve(Inputs.size());
2587330f729Sjoerg   for (const FrontendInputFile &FIF : Inputs) {
2597330f729Sjoerg     // FIXME: We should support re-compiling from an AST file.
2607330f729Sjoerg     if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) {
2617330f729Sjoerg       CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
2627330f729Sjoerg           << (FIF.isFile() ? FIF.getFile()
263*e038c9c4Sjoerg                            : FIF.getBuffer().getBufferIdentifier());
2647330f729Sjoerg       return true;
2657330f729Sjoerg     }
2667330f729Sjoerg 
2677330f729Sjoerg     HeaderContents += "#include \"";
2687330f729Sjoerg     HeaderContents += FIF.getFile();
2697330f729Sjoerg     HeaderContents += "\"\n";
270*e038c9c4Sjoerg     ModuleHeaders.push_back(std::string(FIF.getFile()));
2717330f729Sjoerg   }
2727330f729Sjoerg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(
2737330f729Sjoerg       HeaderContents, Module::getModuleInputBufferName());
2747330f729Sjoerg 
2757330f729Sjoerg   // Set that buffer up as our "real" input.
2767330f729Sjoerg   Inputs.clear();
277*e038c9c4Sjoerg   Inputs.push_back(
278*e038c9c4Sjoerg       FrontendInputFile(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false));
2797330f729Sjoerg 
2807330f729Sjoerg   return GenerateModuleAction::PrepareToExecuteAction(CI);
2817330f729Sjoerg }
2827330f729Sjoerg 
BeginSourceFileAction(CompilerInstance & CI)2837330f729Sjoerg bool GenerateHeaderModuleAction::BeginSourceFileAction(
2847330f729Sjoerg     CompilerInstance &CI) {
2857330f729Sjoerg   CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule);
2867330f729Sjoerg 
2877330f729Sjoerg   // Synthesize a Module object for the given headers.
2887330f729Sjoerg   auto &HS = CI.getPreprocessor().getHeaderSearchInfo();
2897330f729Sjoerg   SmallVector<Module::Header, 16> Headers;
2907330f729Sjoerg   for (StringRef Name : ModuleHeaders) {
2917330f729Sjoerg     const DirectoryLookup *CurDir = nullptr;
2927330f729Sjoerg     Optional<FileEntryRef> FE = HS.LookupFile(
2937330f729Sjoerg         Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None,
2947330f729Sjoerg         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
2957330f729Sjoerg     if (!FE) {
2967330f729Sjoerg       CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
2977330f729Sjoerg         << Name;
2987330f729Sjoerg       continue;
2997330f729Sjoerg     }
300*e038c9c4Sjoerg     Headers.push_back(
301*e038c9c4Sjoerg         {std::string(Name), std::string(Name), &FE->getFileEntry()});
3027330f729Sjoerg   }
3037330f729Sjoerg   HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
3047330f729Sjoerg 
3057330f729Sjoerg   return GenerateModuleAction::BeginSourceFileAction(CI);
3067330f729Sjoerg }
3077330f729Sjoerg 
3087330f729Sjoerg std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)3097330f729Sjoerg GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI,
3107330f729Sjoerg                                              StringRef InFile) {
3117330f729Sjoerg   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
3127330f729Sjoerg }
3137330f729Sjoerg 
~SyntaxOnlyAction()3147330f729Sjoerg SyntaxOnlyAction::~SyntaxOnlyAction() {
3157330f729Sjoerg }
3167330f729Sjoerg 
3177330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)3187330f729Sjoerg SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
3197330f729Sjoerg   return std::make_unique<ASTConsumer>();
3207330f729Sjoerg }
3217330f729Sjoerg 
3227330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)3237330f729Sjoerg DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
3247330f729Sjoerg                                         StringRef InFile) {
3257330f729Sjoerg   return std::make_unique<ASTConsumer>();
3267330f729Sjoerg }
3277330f729Sjoerg 
3287330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)3297330f729Sjoerg VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
3307330f729Sjoerg   return std::make_unique<ASTConsumer>();
3317330f729Sjoerg }
3327330f729Sjoerg 
ExecuteAction()3337330f729Sjoerg void VerifyPCHAction::ExecuteAction() {
3347330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
3357330f729Sjoerg   bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
3367330f729Sjoerg   const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
3377330f729Sjoerg   std::unique_ptr<ASTReader> Reader(new ASTReader(
3387330f729Sjoerg       CI.getPreprocessor(), CI.getModuleCache(), &CI.getASTContext(),
3397330f729Sjoerg       CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions,
3407330f729Sjoerg       Sysroot.empty() ? "" : Sysroot.c_str(),
341*e038c9c4Sjoerg       DisableValidationForModuleKind::None,
342*e038c9c4Sjoerg       /*AllowASTWithCompilerErrors*/ false,
3437330f729Sjoerg       /*AllowConfigurationMismatch*/ true,
3447330f729Sjoerg       /*ValidateSystemInputs*/ true));
3457330f729Sjoerg 
3467330f729Sjoerg   Reader->ReadAST(getCurrentFile(),
3477330f729Sjoerg                   Preamble ? serialization::MK_Preamble
3487330f729Sjoerg                            : serialization::MK_PCH,
3497330f729Sjoerg                   SourceLocation(),
3507330f729Sjoerg                   ASTReader::ARR_ConfigurationMismatch);
3517330f729Sjoerg }
3527330f729Sjoerg 
3537330f729Sjoerg namespace {
3547330f729Sjoerg struct TemplightEntry {
3557330f729Sjoerg   std::string Name;
3567330f729Sjoerg   std::string Kind;
3577330f729Sjoerg   std::string Event;
3587330f729Sjoerg   std::string DefinitionLocation;
3597330f729Sjoerg   std::string PointOfInstantiation;
3607330f729Sjoerg };
3617330f729Sjoerg } // namespace
3627330f729Sjoerg 
3637330f729Sjoerg namespace llvm {
3647330f729Sjoerg namespace yaml {
3657330f729Sjoerg template <> struct MappingTraits<TemplightEntry> {
mappingllvm::yaml::MappingTraits3667330f729Sjoerg   static void mapping(IO &io, TemplightEntry &fields) {
3677330f729Sjoerg     io.mapRequired("name", fields.Name);
3687330f729Sjoerg     io.mapRequired("kind", fields.Kind);
3697330f729Sjoerg     io.mapRequired("event", fields.Event);
3707330f729Sjoerg     io.mapRequired("orig", fields.DefinitionLocation);
3717330f729Sjoerg     io.mapRequired("poi", fields.PointOfInstantiation);
3727330f729Sjoerg   }
3737330f729Sjoerg };
3747330f729Sjoerg } // namespace yaml
3757330f729Sjoerg } // namespace llvm
3767330f729Sjoerg 
3777330f729Sjoerg namespace {
3787330f729Sjoerg class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
3797330f729Sjoerg   using CodeSynthesisContext = Sema::CodeSynthesisContext;
3807330f729Sjoerg 
3817330f729Sjoerg public:
initialize(const Sema &)3827330f729Sjoerg   void initialize(const Sema &) override {}
3837330f729Sjoerg 
finalize(const Sema &)3847330f729Sjoerg   void finalize(const Sema &) override {}
3857330f729Sjoerg 
atTemplateBegin(const Sema & TheSema,const CodeSynthesisContext & Inst)3867330f729Sjoerg   void atTemplateBegin(const Sema &TheSema,
3877330f729Sjoerg                        const CodeSynthesisContext &Inst) override {
3887330f729Sjoerg     displayTemplightEntry<true>(llvm::outs(), TheSema, Inst);
3897330f729Sjoerg   }
3907330f729Sjoerg 
atTemplateEnd(const Sema & TheSema,const CodeSynthesisContext & Inst)3917330f729Sjoerg   void atTemplateEnd(const Sema &TheSema,
3927330f729Sjoerg                      const CodeSynthesisContext &Inst) override {
3937330f729Sjoerg     displayTemplightEntry<false>(llvm::outs(), TheSema, Inst);
3947330f729Sjoerg   }
3957330f729Sjoerg 
3967330f729Sjoerg private:
toString(CodeSynthesisContext::SynthesisKind Kind)3977330f729Sjoerg   static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
3987330f729Sjoerg     switch (Kind) {
3997330f729Sjoerg     case CodeSynthesisContext::TemplateInstantiation:
4007330f729Sjoerg       return "TemplateInstantiation";
4017330f729Sjoerg     case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
4027330f729Sjoerg       return "DefaultTemplateArgumentInstantiation";
4037330f729Sjoerg     case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
4047330f729Sjoerg       return "DefaultFunctionArgumentInstantiation";
4057330f729Sjoerg     case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
4067330f729Sjoerg       return "ExplicitTemplateArgumentSubstitution";
4077330f729Sjoerg     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
4087330f729Sjoerg       return "DeducedTemplateArgumentSubstitution";
4097330f729Sjoerg     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
4107330f729Sjoerg       return "PriorTemplateArgumentSubstitution";
4117330f729Sjoerg     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
4127330f729Sjoerg       return "DefaultTemplateArgumentChecking";
4137330f729Sjoerg     case CodeSynthesisContext::ExceptionSpecEvaluation:
4147330f729Sjoerg       return "ExceptionSpecEvaluation";
4157330f729Sjoerg     case CodeSynthesisContext::ExceptionSpecInstantiation:
4167330f729Sjoerg       return "ExceptionSpecInstantiation";
4177330f729Sjoerg     case CodeSynthesisContext::DeclaringSpecialMember:
4187330f729Sjoerg       return "DeclaringSpecialMember";
419*e038c9c4Sjoerg     case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
420*e038c9c4Sjoerg       return "DeclaringImplicitEqualityComparison";
4217330f729Sjoerg     case CodeSynthesisContext::DefiningSynthesizedFunction:
4227330f729Sjoerg       return "DefiningSynthesizedFunction";
4237330f729Sjoerg     case CodeSynthesisContext::RewritingOperatorAsSpaceship:
4247330f729Sjoerg       return "RewritingOperatorAsSpaceship";
4257330f729Sjoerg     case CodeSynthesisContext::Memoization:
4267330f729Sjoerg       return "Memoization";
4277330f729Sjoerg     case CodeSynthesisContext::ConstraintsCheck:
4287330f729Sjoerg       return "ConstraintsCheck";
4297330f729Sjoerg     case CodeSynthesisContext::ConstraintSubstitution:
4307330f729Sjoerg       return "ConstraintSubstitution";
431*e038c9c4Sjoerg     case CodeSynthesisContext::ConstraintNormalization:
432*e038c9c4Sjoerg       return "ConstraintNormalization";
433*e038c9c4Sjoerg     case CodeSynthesisContext::ParameterMappingSubstitution:
434*e038c9c4Sjoerg       return "ParameterMappingSubstitution";
435*e038c9c4Sjoerg     case CodeSynthesisContext::RequirementInstantiation:
436*e038c9c4Sjoerg       return "RequirementInstantiation";
437*e038c9c4Sjoerg     case CodeSynthesisContext::NestedRequirementConstraintsCheck:
438*e038c9c4Sjoerg       return "NestedRequirementConstraintsCheck";
439*e038c9c4Sjoerg     case CodeSynthesisContext::InitializingStructuredBinding:
440*e038c9c4Sjoerg       return "InitializingStructuredBinding";
441*e038c9c4Sjoerg     case CodeSynthesisContext::MarkingClassDllexported:
442*e038c9c4Sjoerg       return "MarkingClassDllexported";
4437330f729Sjoerg     }
4447330f729Sjoerg     return "";
4457330f729Sjoerg   }
4467330f729Sjoerg 
4477330f729Sjoerg   template <bool BeginInstantiation>
displayTemplightEntry(llvm::raw_ostream & Out,const Sema & TheSema,const CodeSynthesisContext & Inst)4487330f729Sjoerg   static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema,
4497330f729Sjoerg                                     const CodeSynthesisContext &Inst) {
4507330f729Sjoerg     std::string YAML;
4517330f729Sjoerg     {
4527330f729Sjoerg       llvm::raw_string_ostream OS(YAML);
4537330f729Sjoerg       llvm::yaml::Output YO(OS);
4547330f729Sjoerg       TemplightEntry Entry =
4557330f729Sjoerg           getTemplightEntry<BeginInstantiation>(TheSema, Inst);
4567330f729Sjoerg       llvm::yaml::EmptyContext Context;
4577330f729Sjoerg       llvm::yaml::yamlize(YO, Entry, true, Context);
4587330f729Sjoerg     }
4597330f729Sjoerg     Out << "---" << YAML << "\n";
4607330f729Sjoerg   }
4617330f729Sjoerg 
4627330f729Sjoerg   template <bool BeginInstantiation>
getTemplightEntry(const Sema & TheSema,const CodeSynthesisContext & Inst)4637330f729Sjoerg   static TemplightEntry getTemplightEntry(const Sema &TheSema,
4647330f729Sjoerg                                           const CodeSynthesisContext &Inst) {
4657330f729Sjoerg     TemplightEntry Entry;
4667330f729Sjoerg     Entry.Kind = toString(Inst.Kind);
4677330f729Sjoerg     Entry.Event = BeginInstantiation ? "Begin" : "End";
4687330f729Sjoerg     if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) {
4697330f729Sjoerg       llvm::raw_string_ostream OS(Entry.Name);
470*e038c9c4Sjoerg       PrintingPolicy Policy = TheSema.Context.getPrintingPolicy();
471*e038c9c4Sjoerg       // FIXME: Also ask for FullyQualifiedNames?
472*e038c9c4Sjoerg       Policy.SuppressDefaultTemplateArgs = false;
473*e038c9c4Sjoerg       NamedTemplate->getNameForDiagnostic(OS, Policy, true);
4747330f729Sjoerg       const PresumedLoc DefLoc =
4757330f729Sjoerg         TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation());
4767330f729Sjoerg       if(!DefLoc.isInvalid())
4777330f729Sjoerg         Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" +
4787330f729Sjoerg                                    std::to_string(DefLoc.getLine()) + ":" +
4797330f729Sjoerg                                    std::to_string(DefLoc.getColumn());
4807330f729Sjoerg     }
4817330f729Sjoerg     const PresumedLoc PoiLoc =
4827330f729Sjoerg         TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation);
4837330f729Sjoerg     if (!PoiLoc.isInvalid()) {
4847330f729Sjoerg       Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" +
4857330f729Sjoerg                                    std::to_string(PoiLoc.getLine()) + ":" +
4867330f729Sjoerg                                    std::to_string(PoiLoc.getColumn());
4877330f729Sjoerg     }
4887330f729Sjoerg     return Entry;
4897330f729Sjoerg   }
4907330f729Sjoerg };
4917330f729Sjoerg } // namespace
4927330f729Sjoerg 
4937330f729Sjoerg std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)4947330f729Sjoerg TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
4957330f729Sjoerg   return std::make_unique<ASTConsumer>();
4967330f729Sjoerg }
4977330f729Sjoerg 
ExecuteAction()4987330f729Sjoerg void TemplightDumpAction::ExecuteAction() {
4997330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
5007330f729Sjoerg 
5017330f729Sjoerg   // This part is normally done by ASTFrontEndAction, but needs to happen
5027330f729Sjoerg   // before Templight observers can be created
5037330f729Sjoerg   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
5047330f729Sjoerg   // here so the source manager would be initialized.
5057330f729Sjoerg   EnsureSemaIsCreated(CI, *this);
5067330f729Sjoerg 
5077330f729Sjoerg   CI.getSema().TemplateInstCallbacks.push_back(
5087330f729Sjoerg       std::make_unique<DefaultTemplateInstCallback>());
5097330f729Sjoerg   ASTFrontendAction::ExecuteAction();
5107330f729Sjoerg }
5117330f729Sjoerg 
5127330f729Sjoerg namespace {
5137330f729Sjoerg   /// AST reader listener that dumps module information for a module
5147330f729Sjoerg   /// file.
5157330f729Sjoerg   class DumpModuleInfoListener : public ASTReaderListener {
5167330f729Sjoerg     llvm::raw_ostream &Out;
5177330f729Sjoerg 
5187330f729Sjoerg   public:
DumpModuleInfoListener(llvm::raw_ostream & Out)5197330f729Sjoerg     DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { }
5207330f729Sjoerg 
5217330f729Sjoerg #define DUMP_BOOLEAN(Value, Text)                       \
5227330f729Sjoerg     Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
5237330f729Sjoerg 
ReadFullVersionInformation(StringRef FullVersion)5247330f729Sjoerg     bool ReadFullVersionInformation(StringRef FullVersion) override {
5257330f729Sjoerg       Out.indent(2)
5267330f729Sjoerg         << "Generated by "
5277330f729Sjoerg         << (FullVersion == getClangFullRepositoryVersion()? "this"
5287330f729Sjoerg                                                           : "a different")
5297330f729Sjoerg         << " Clang: " << FullVersion << "\n";
5307330f729Sjoerg       return ASTReaderListener::ReadFullVersionInformation(FullVersion);
5317330f729Sjoerg     }
5327330f729Sjoerg 
ReadModuleName(StringRef ModuleName)5337330f729Sjoerg     void ReadModuleName(StringRef ModuleName) override {
5347330f729Sjoerg       Out.indent(2) << "Module name: " << ModuleName << "\n";
5357330f729Sjoerg     }
ReadModuleMapFile(StringRef ModuleMapPath)5367330f729Sjoerg     void ReadModuleMapFile(StringRef ModuleMapPath) override {
5377330f729Sjoerg       Out.indent(2) << "Module map file: " << ModuleMapPath << "\n";
5387330f729Sjoerg     }
5397330f729Sjoerg 
ReadLanguageOptions(const LangOptions & LangOpts,bool Complain,bool AllowCompatibleDifferences)5407330f729Sjoerg     bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
5417330f729Sjoerg                              bool AllowCompatibleDifferences) override {
5427330f729Sjoerg       Out.indent(2) << "Language options:\n";
5437330f729Sjoerg #define LANGOPT(Name, Bits, Default, Description) \
5447330f729Sjoerg       DUMP_BOOLEAN(LangOpts.Name, Description);
5457330f729Sjoerg #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
5467330f729Sjoerg       Out.indent(4) << Description << ": "                   \
5477330f729Sjoerg                     << static_cast<unsigned>(LangOpts.get##Name()) << "\n";
5487330f729Sjoerg #define VALUE_LANGOPT(Name, Bits, Default, Description) \
5497330f729Sjoerg       Out.indent(4) << Description << ": " << LangOpts.Name << "\n";
5507330f729Sjoerg #define BENIGN_LANGOPT(Name, Bits, Default, Description)
5517330f729Sjoerg #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
5527330f729Sjoerg #include "clang/Basic/LangOptions.def"
5537330f729Sjoerg 
5547330f729Sjoerg       if (!LangOpts.ModuleFeatures.empty()) {
5557330f729Sjoerg         Out.indent(4) << "Module features:\n";
5567330f729Sjoerg         for (StringRef Feature : LangOpts.ModuleFeatures)
5577330f729Sjoerg           Out.indent(6) << Feature << "\n";
5587330f729Sjoerg       }
5597330f729Sjoerg 
5607330f729Sjoerg       return false;
5617330f729Sjoerg     }
5627330f729Sjoerg 
ReadTargetOptions(const TargetOptions & TargetOpts,bool Complain,bool AllowCompatibleDifferences)5637330f729Sjoerg     bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
5647330f729Sjoerg                            bool AllowCompatibleDifferences) override {
5657330f729Sjoerg       Out.indent(2) << "Target options:\n";
5667330f729Sjoerg       Out.indent(4) << "  Triple: " << TargetOpts.Triple << "\n";
5677330f729Sjoerg       Out.indent(4) << "  CPU: " << TargetOpts.CPU << "\n";
568*e038c9c4Sjoerg       Out.indent(4) << "  TuneCPU: " << TargetOpts.TuneCPU << "\n";
5697330f729Sjoerg       Out.indent(4) << "  ABI: " << TargetOpts.ABI << "\n";
5707330f729Sjoerg 
5717330f729Sjoerg       if (!TargetOpts.FeaturesAsWritten.empty()) {
5727330f729Sjoerg         Out.indent(4) << "Target features:\n";
5737330f729Sjoerg         for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size();
5747330f729Sjoerg              I != N; ++I) {
5757330f729Sjoerg           Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n";
5767330f729Sjoerg         }
5777330f729Sjoerg       }
5787330f729Sjoerg 
5797330f729Sjoerg       return false;
5807330f729Sjoerg     }
5817330f729Sjoerg 
ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,bool Complain)5827330f729Sjoerg     bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
5837330f729Sjoerg                                bool Complain) override {
5847330f729Sjoerg       Out.indent(2) << "Diagnostic options:\n";
5857330f729Sjoerg #define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
5867330f729Sjoerg #define ENUM_DIAGOPT(Name, Type, Bits, Default) \
5877330f729Sjoerg       Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
5887330f729Sjoerg #define VALUE_DIAGOPT(Name, Bits, Default) \
5897330f729Sjoerg       Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
5907330f729Sjoerg #include "clang/Basic/DiagnosticOptions.def"
5917330f729Sjoerg 
5927330f729Sjoerg       Out.indent(4) << "Diagnostic flags:\n";
5937330f729Sjoerg       for (const std::string &Warning : DiagOpts->Warnings)
5947330f729Sjoerg         Out.indent(6) << "-W" << Warning << "\n";
5957330f729Sjoerg       for (const std::string &Remark : DiagOpts->Remarks)
5967330f729Sjoerg         Out.indent(6) << "-R" << Remark << "\n";
5977330f729Sjoerg 
5987330f729Sjoerg       return false;
5997330f729Sjoerg     }
6007330f729Sjoerg 
ReadHeaderSearchOptions(const HeaderSearchOptions & HSOpts,StringRef SpecificModuleCachePath,bool Complain)6017330f729Sjoerg     bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
6027330f729Sjoerg                                  StringRef SpecificModuleCachePath,
6037330f729Sjoerg                                  bool Complain) override {
6047330f729Sjoerg       Out.indent(2) << "Header search options:\n";
6057330f729Sjoerg       Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
6067330f729Sjoerg       Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n";
6077330f729Sjoerg       Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n";
6087330f729Sjoerg       DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
6097330f729Sjoerg                    "Use builtin include directories [-nobuiltininc]");
6107330f729Sjoerg       DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes,
6117330f729Sjoerg                    "Use standard system include directories [-nostdinc]");
6127330f729Sjoerg       DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes,
6137330f729Sjoerg                    "Use standard C++ include directories [-nostdinc++]");
6147330f729Sjoerg       DUMP_BOOLEAN(HSOpts.UseLibcxx,
6157330f729Sjoerg                    "Use libc++ (rather than libstdc++) [-stdlib=]");
6167330f729Sjoerg       return false;
6177330f729Sjoerg     }
6187330f729Sjoerg 
ReadPreprocessorOptions(const PreprocessorOptions & PPOpts,bool Complain,std::string & SuggestedPredefines)6197330f729Sjoerg     bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
6207330f729Sjoerg                                  bool Complain,
6217330f729Sjoerg                                  std::string &SuggestedPredefines) override {
6227330f729Sjoerg       Out.indent(2) << "Preprocessor options:\n";
6237330f729Sjoerg       DUMP_BOOLEAN(PPOpts.UsePredefines,
6247330f729Sjoerg                    "Uses compiler/target-specific predefines [-undef]");
6257330f729Sjoerg       DUMP_BOOLEAN(PPOpts.DetailedRecord,
6267330f729Sjoerg                    "Uses detailed preprocessing record (for indexing)");
6277330f729Sjoerg 
6287330f729Sjoerg       if (!PPOpts.Macros.empty()) {
6297330f729Sjoerg         Out.indent(4) << "Predefined macros:\n";
6307330f729Sjoerg       }
6317330f729Sjoerg 
6327330f729Sjoerg       for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
6337330f729Sjoerg              I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end();
6347330f729Sjoerg            I != IEnd; ++I) {
6357330f729Sjoerg         Out.indent(6);
6367330f729Sjoerg         if (I->second)
6377330f729Sjoerg           Out << "-U";
6387330f729Sjoerg         else
6397330f729Sjoerg           Out << "-D";
6407330f729Sjoerg         Out << I->first << "\n";
6417330f729Sjoerg       }
6427330f729Sjoerg       return false;
6437330f729Sjoerg     }
6447330f729Sjoerg 
6457330f729Sjoerg     /// Indicates that a particular module file extension has been read.
readModuleFileExtension(const ModuleFileExtensionMetadata & Metadata)6467330f729Sjoerg     void readModuleFileExtension(
6477330f729Sjoerg            const ModuleFileExtensionMetadata &Metadata) override {
6487330f729Sjoerg       Out.indent(2) << "Module file extension '"
6497330f729Sjoerg                     << Metadata.BlockName << "' " << Metadata.MajorVersion
6507330f729Sjoerg                     << "." << Metadata.MinorVersion;
6517330f729Sjoerg       if (!Metadata.UserInfo.empty()) {
6527330f729Sjoerg         Out << ": ";
6537330f729Sjoerg         Out.write_escaped(Metadata.UserInfo);
6547330f729Sjoerg       }
6557330f729Sjoerg 
6567330f729Sjoerg       Out << "\n";
6577330f729Sjoerg     }
6587330f729Sjoerg 
6597330f729Sjoerg     /// Tells the \c ASTReaderListener that we want to receive the
6607330f729Sjoerg     /// input files of the AST file via \c visitInputFile.
needsInputFileVisitation()6617330f729Sjoerg     bool needsInputFileVisitation() override { return true; }
6627330f729Sjoerg 
6637330f729Sjoerg     /// Tells the \c ASTReaderListener that we want to receive the
6647330f729Sjoerg     /// input files of the AST file via \c visitInputFile.
needsSystemInputFileVisitation()6657330f729Sjoerg     bool needsSystemInputFileVisitation() override { return true; }
6667330f729Sjoerg 
6677330f729Sjoerg     /// Indicates that the AST file contains particular input file.
6687330f729Sjoerg     ///
6697330f729Sjoerg     /// \returns true to continue receiving the next input file, false to stop.
visitInputFile(StringRef Filename,bool isSystem,bool isOverridden,bool isExplicitModule)6707330f729Sjoerg     bool visitInputFile(StringRef Filename, bool isSystem,
6717330f729Sjoerg                         bool isOverridden, bool isExplicitModule) override {
6727330f729Sjoerg 
6737330f729Sjoerg       Out.indent(2) << "Input file: " << Filename;
6747330f729Sjoerg 
6757330f729Sjoerg       if (isSystem || isOverridden || isExplicitModule) {
6767330f729Sjoerg         Out << " [";
6777330f729Sjoerg         if (isSystem) {
6787330f729Sjoerg           Out << "System";
6797330f729Sjoerg           if (isOverridden || isExplicitModule)
6807330f729Sjoerg             Out << ", ";
6817330f729Sjoerg         }
6827330f729Sjoerg         if (isOverridden) {
6837330f729Sjoerg           Out << "Overridden";
6847330f729Sjoerg           if (isExplicitModule)
6857330f729Sjoerg             Out << ", ";
6867330f729Sjoerg         }
6877330f729Sjoerg         if (isExplicitModule)
6887330f729Sjoerg           Out << "ExplicitModule";
6897330f729Sjoerg 
6907330f729Sjoerg         Out << "]";
6917330f729Sjoerg       }
6927330f729Sjoerg 
6937330f729Sjoerg       Out << "\n";
6947330f729Sjoerg 
6957330f729Sjoerg       return true;
6967330f729Sjoerg     }
6977330f729Sjoerg 
6987330f729Sjoerg     /// Returns true if this \c ASTReaderListener wants to receive the
6997330f729Sjoerg     /// imports of the AST file via \c visitImport, false otherwise.
needsImportVisitation() const7007330f729Sjoerg     bool needsImportVisitation() const override { return true; }
7017330f729Sjoerg 
7027330f729Sjoerg     /// If needsImportVisitation returns \c true, this is called for each
7037330f729Sjoerg     /// AST file imported by this AST file.
visitImport(StringRef ModuleName,StringRef Filename)7047330f729Sjoerg     void visitImport(StringRef ModuleName, StringRef Filename) override {
7057330f729Sjoerg       Out.indent(2) << "Imports module '" << ModuleName
7067330f729Sjoerg                     << "': " << Filename.str() << "\n";
7077330f729Sjoerg     }
7087330f729Sjoerg #undef DUMP_BOOLEAN
7097330f729Sjoerg   };
7107330f729Sjoerg }
7117330f729Sjoerg 
BeginInvocation(CompilerInstance & CI)7127330f729Sjoerg bool DumpModuleInfoAction::BeginInvocation(CompilerInstance &CI) {
7137330f729Sjoerg   // The Object file reader also supports raw ast files and there is no point in
7147330f729Sjoerg   // being strict about the module file format in -module-file-info mode.
7157330f729Sjoerg   CI.getHeaderSearchOpts().ModuleFormat = "obj";
7167330f729Sjoerg   return true;
7177330f729Sjoerg }
7187330f729Sjoerg 
ExecuteAction()7197330f729Sjoerg void DumpModuleInfoAction::ExecuteAction() {
7207330f729Sjoerg   // Set up the output file.
7217330f729Sjoerg   std::unique_ptr<llvm::raw_fd_ostream> OutFile;
7227330f729Sjoerg   StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile;
7237330f729Sjoerg   if (!OutputFileName.empty() && OutputFileName != "-") {
7247330f729Sjoerg     std::error_code EC;
7257330f729Sjoerg     OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
726*e038c9c4Sjoerg                                            llvm::sys::fs::OF_TextWithCRLF));
7277330f729Sjoerg   }
7287330f729Sjoerg   llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
7297330f729Sjoerg 
7307330f729Sjoerg   Out << "Information for module file '" << getCurrentFile() << "':\n";
7317330f729Sjoerg   auto &FileMgr = getCompilerInstance().getFileManager();
7327330f729Sjoerg   auto Buffer = FileMgr.getBufferForFile(getCurrentFile());
7337330f729Sjoerg   StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer();
7347330f729Sjoerg   bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P' &&
7357330f729Sjoerg                 Magic[2] == 'C' && Magic[3] == 'H');
7367330f729Sjoerg   Out << "  Module format: " << (IsRaw ? "raw" : "obj") << "\n";
7377330f729Sjoerg 
7387330f729Sjoerg   Preprocessor &PP = getCompilerInstance().getPreprocessor();
7397330f729Sjoerg   DumpModuleInfoListener Listener(Out);
7407330f729Sjoerg   HeaderSearchOptions &HSOpts =
7417330f729Sjoerg       PP.getHeaderSearchInfo().getHeaderSearchOpts();
7427330f729Sjoerg   ASTReader::readASTFileControlBlock(
7437330f729Sjoerg       getCurrentFile(), FileMgr, getCompilerInstance().getPCHContainerReader(),
7447330f729Sjoerg       /*FindModuleFileExtensions=*/true, Listener,
7457330f729Sjoerg       HSOpts.ModulesValidateDiagnosticOptions);
7467330f729Sjoerg }
7477330f729Sjoerg 
7487330f729Sjoerg //===----------------------------------------------------------------------===//
7497330f729Sjoerg // Preprocessor Actions
7507330f729Sjoerg //===----------------------------------------------------------------------===//
7517330f729Sjoerg 
ExecuteAction()7527330f729Sjoerg void DumpRawTokensAction::ExecuteAction() {
7537330f729Sjoerg   Preprocessor &PP = getCompilerInstance().getPreprocessor();
7547330f729Sjoerg   SourceManager &SM = PP.getSourceManager();
7557330f729Sjoerg 
7567330f729Sjoerg   // Start lexing the specified input file.
757*e038c9c4Sjoerg   llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID());
7587330f729Sjoerg   Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
7597330f729Sjoerg   RawLex.SetKeepWhitespaceMode(true);
7607330f729Sjoerg 
7617330f729Sjoerg   Token RawTok;
7627330f729Sjoerg   RawLex.LexFromRawLexer(RawTok);
7637330f729Sjoerg   while (RawTok.isNot(tok::eof)) {
7647330f729Sjoerg     PP.DumpToken(RawTok, true);
7657330f729Sjoerg     llvm::errs() << "\n";
7667330f729Sjoerg     RawLex.LexFromRawLexer(RawTok);
7677330f729Sjoerg   }
7687330f729Sjoerg }
7697330f729Sjoerg 
ExecuteAction()7707330f729Sjoerg void DumpTokensAction::ExecuteAction() {
7717330f729Sjoerg   Preprocessor &PP = getCompilerInstance().getPreprocessor();
7727330f729Sjoerg   // Start preprocessing the specified input file.
7737330f729Sjoerg   Token Tok;
7747330f729Sjoerg   PP.EnterMainSourceFile();
7757330f729Sjoerg   do {
7767330f729Sjoerg     PP.Lex(Tok);
7777330f729Sjoerg     PP.DumpToken(Tok, true);
7787330f729Sjoerg     llvm::errs() << "\n";
7797330f729Sjoerg   } while (Tok.isNot(tok::eof));
7807330f729Sjoerg }
7817330f729Sjoerg 
ExecuteAction()7827330f729Sjoerg void PreprocessOnlyAction::ExecuteAction() {
7837330f729Sjoerg   Preprocessor &PP = getCompilerInstance().getPreprocessor();
7847330f729Sjoerg 
7857330f729Sjoerg   // Ignore unknown pragmas.
7867330f729Sjoerg   PP.IgnorePragmas();
7877330f729Sjoerg 
7887330f729Sjoerg   Token Tok;
7897330f729Sjoerg   // Start parsing the specified input file.
7907330f729Sjoerg   PP.EnterMainSourceFile();
7917330f729Sjoerg   do {
7927330f729Sjoerg     PP.Lex(Tok);
7937330f729Sjoerg   } while (Tok.isNot(tok::eof));
7947330f729Sjoerg }
7957330f729Sjoerg 
ExecuteAction()7967330f729Sjoerg void PrintPreprocessedAction::ExecuteAction() {
7977330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
7987330f729Sjoerg   // Output file may need to be set to 'Binary', to avoid converting Unix style
799*e038c9c4Sjoerg   // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>) on Windows.
8007330f729Sjoerg   //
8017330f729Sjoerg   // Look to see what type of line endings the file uses. If there's a
8027330f729Sjoerg   // CRLF, then we won't open the file up in binary mode. If there is
8037330f729Sjoerg   // just an LF or CR, then we will open the file up in binary mode.
8047330f729Sjoerg   // In this fashion, the output format should match the input format, unless
8057330f729Sjoerg   // the input format has inconsistent line endings.
8067330f729Sjoerg   //
8077330f729Sjoerg   // This should be a relatively fast operation since most files won't have
8087330f729Sjoerg   // all of their source code on a single line. However, that is still a
8097330f729Sjoerg   // concern, so if we scan for too long, we'll just assume the file should
8107330f729Sjoerg   // be opened in binary mode.
811*e038c9c4Sjoerg 
812*e038c9c4Sjoerg   bool BinaryMode = false;
813*e038c9c4Sjoerg   if (llvm::Triple(LLVM_HOST_TRIPLE).isOSWindows()) {
814*e038c9c4Sjoerg     BinaryMode = true;
8157330f729Sjoerg     const SourceManager &SM = CI.getSourceManager();
816*e038c9c4Sjoerg     if (llvm::Optional<llvm::MemoryBufferRef> Buffer =
817*e038c9c4Sjoerg             SM.getBufferOrNone(SM.getMainFileID())) {
8187330f729Sjoerg       const char *cur = Buffer->getBufferStart();
8197330f729Sjoerg       const char *end = Buffer->getBufferEnd();
8207330f729Sjoerg       const char *next = (cur != end) ? cur + 1 : end;
8217330f729Sjoerg 
8227330f729Sjoerg       // Limit ourselves to only scanning 256 characters into the source
8237330f729Sjoerg       // file.  This is mostly a sanity check in case the file has no
8247330f729Sjoerg       // newlines whatsoever.
825*e038c9c4Sjoerg       if (end - cur > 256)
826*e038c9c4Sjoerg         end = cur + 256;
8277330f729Sjoerg 
8287330f729Sjoerg       while (next < end) {
8297330f729Sjoerg         if (*cur == 0x0D) {  // CR
8307330f729Sjoerg           if (*next == 0x0A) // CRLF
8317330f729Sjoerg             BinaryMode = false;
8327330f729Sjoerg 
8337330f729Sjoerg           break;
8347330f729Sjoerg         } else if (*cur == 0x0A) // LF
8357330f729Sjoerg           break;
8367330f729Sjoerg 
8377330f729Sjoerg         ++cur;
8387330f729Sjoerg         ++next;
8397330f729Sjoerg       }
8407330f729Sjoerg     }
841*e038c9c4Sjoerg   }
8427330f729Sjoerg 
8437330f729Sjoerg   std::unique_ptr<raw_ostream> OS =
8447330f729Sjoerg       CI.createDefaultOutputFile(BinaryMode, getCurrentFileOrBufferName());
8457330f729Sjoerg   if (!OS) return;
8467330f729Sjoerg 
8477330f729Sjoerg   // If we're preprocessing a module map, start by dumping the contents of the
8487330f729Sjoerg   // module itself before switching to the input buffer.
8497330f729Sjoerg   auto &Input = getCurrentInput();
8507330f729Sjoerg   if (Input.getKind().getFormat() == InputKind::ModuleMap) {
8517330f729Sjoerg     if (Input.isFile()) {
8527330f729Sjoerg       (*OS) << "# 1 \"";
8537330f729Sjoerg       OS->write_escaped(Input.getFile());
8547330f729Sjoerg       (*OS) << "\"\n";
8557330f729Sjoerg     }
8567330f729Sjoerg     getCurrentModule()->print(*OS);
8577330f729Sjoerg     (*OS) << "#pragma clang module contents\n";
8587330f729Sjoerg   }
8597330f729Sjoerg 
8607330f729Sjoerg   DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(),
8617330f729Sjoerg                            CI.getPreprocessorOutputOpts());
8627330f729Sjoerg }
8637330f729Sjoerg 
ExecuteAction()8647330f729Sjoerg void PrintPreambleAction::ExecuteAction() {
8657330f729Sjoerg   switch (getCurrentFileKind().getLanguage()) {
8667330f729Sjoerg   case Language::C:
8677330f729Sjoerg   case Language::CXX:
8687330f729Sjoerg   case Language::ObjC:
8697330f729Sjoerg   case Language::ObjCXX:
8707330f729Sjoerg   case Language::OpenCL:
871*e038c9c4Sjoerg   case Language::OpenCLCXX:
8727330f729Sjoerg   case Language::CUDA:
8737330f729Sjoerg   case Language::HIP:
8747330f729Sjoerg     break;
8757330f729Sjoerg 
8767330f729Sjoerg   case Language::Unknown:
8777330f729Sjoerg   case Language::Asm:
8787330f729Sjoerg   case Language::LLVM_IR:
8797330f729Sjoerg   case Language::RenderScript:
8807330f729Sjoerg     // We can't do anything with these.
8817330f729Sjoerg     return;
8827330f729Sjoerg   }
8837330f729Sjoerg 
8847330f729Sjoerg   // We don't expect to find any #include directives in a preprocessed input.
8857330f729Sjoerg   if (getCurrentFileKind().isPreprocessed())
8867330f729Sjoerg     return;
8877330f729Sjoerg 
8887330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
8897330f729Sjoerg   auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
8907330f729Sjoerg   if (Buffer) {
8917330f729Sjoerg     unsigned Preamble =
8927330f729Sjoerg         Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).Size;
8937330f729Sjoerg     llvm::outs().write((*Buffer)->getBufferStart(), Preamble);
8947330f729Sjoerg   }
8957330f729Sjoerg }
8967330f729Sjoerg 
ExecuteAction()8977330f729Sjoerg void DumpCompilerOptionsAction::ExecuteAction() {
8987330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
8997330f729Sjoerg   std::unique_ptr<raw_ostream> OSP =
9007330f729Sjoerg       CI.createDefaultOutputFile(false, getCurrentFile());
9017330f729Sjoerg   if (!OSP)
9027330f729Sjoerg     return;
9037330f729Sjoerg 
9047330f729Sjoerg   raw_ostream &OS = *OSP;
9057330f729Sjoerg   const Preprocessor &PP = CI.getPreprocessor();
9067330f729Sjoerg   const LangOptions &LangOpts = PP.getLangOpts();
9077330f729Sjoerg 
9087330f729Sjoerg   // FIXME: Rather than manually format the JSON (which is awkward due to
9097330f729Sjoerg   // needing to remove trailing commas), this should make use of a JSON library.
9107330f729Sjoerg   // FIXME: Instead of printing enums as an integral value and specifying the
9117330f729Sjoerg   // type as a separate field, use introspection to print the enumerator.
9127330f729Sjoerg 
9137330f729Sjoerg   OS << "{\n";
9147330f729Sjoerg   OS << "\n\"features\" : [\n";
9157330f729Sjoerg   {
9167330f729Sjoerg     llvm::SmallString<128> Str;
9177330f729Sjoerg #define FEATURE(Name, Predicate)                                               \
9187330f729Sjoerg   ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \
9197330f729Sjoerg       .toVector(Str);
9207330f729Sjoerg #include "clang/Basic/Features.def"
9217330f729Sjoerg #undef FEATURE
9227330f729Sjoerg     // Remove the newline and comma from the last entry to ensure this remains
9237330f729Sjoerg     // valid JSON.
9247330f729Sjoerg     OS << Str.substr(0, Str.size() - 2);
9257330f729Sjoerg   }
9267330f729Sjoerg   OS << "\n],\n";
9277330f729Sjoerg 
9287330f729Sjoerg   OS << "\n\"extensions\" : [\n";
9297330f729Sjoerg   {
9307330f729Sjoerg     llvm::SmallString<128> Str;
9317330f729Sjoerg #define EXTENSION(Name, Predicate)                                             \
9327330f729Sjoerg   ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \
9337330f729Sjoerg       .toVector(Str);
9347330f729Sjoerg #include "clang/Basic/Features.def"
9357330f729Sjoerg #undef EXTENSION
9367330f729Sjoerg     // Remove the newline and comma from the last entry to ensure this remains
9377330f729Sjoerg     // valid JSON.
9387330f729Sjoerg     OS << Str.substr(0, Str.size() - 2);
9397330f729Sjoerg   }
9407330f729Sjoerg   OS << "\n]\n";
9417330f729Sjoerg 
9427330f729Sjoerg   OS << "}";
9437330f729Sjoerg }
9447330f729Sjoerg 
ExecuteAction()9457330f729Sjoerg void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
9467330f729Sjoerg   CompilerInstance &CI = getCompilerInstance();
9477330f729Sjoerg   SourceManager &SM = CI.getPreprocessor().getSourceManager();
948*e038c9c4Sjoerg   llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID());
9497330f729Sjoerg 
9507330f729Sjoerg   llvm::SmallString<1024> Output;
9517330f729Sjoerg   llvm::SmallVector<minimize_source_to_dependency_directives::Token, 32> Toks;
9527330f729Sjoerg   if (minimizeSourceToDependencyDirectives(
953*e038c9c4Sjoerg           FromFile.getBuffer(), Output, Toks, &CI.getDiagnostics(),
9547330f729Sjoerg           SM.getLocForStartOfFile(SM.getMainFileID()))) {
9557330f729Sjoerg     assert(CI.getDiagnostics().hasErrorOccurred() &&
9567330f729Sjoerg            "no errors reported for failure");
9577330f729Sjoerg 
9587330f729Sjoerg     // Preprocess the source when verifying the diagnostics to capture the
9597330f729Sjoerg     // 'expected' comments.
9607330f729Sjoerg     if (CI.getDiagnosticOpts().VerifyDiagnostics) {
9617330f729Sjoerg       // Make sure we don't emit new diagnostics!
9627330f729Sjoerg       CI.getDiagnostics().setSuppressAllDiagnostics(true);
9637330f729Sjoerg       Preprocessor &PP = getCompilerInstance().getPreprocessor();
9647330f729Sjoerg       PP.EnterMainSourceFile();
9657330f729Sjoerg       Token Tok;
9667330f729Sjoerg       do {
9677330f729Sjoerg         PP.Lex(Tok);
9687330f729Sjoerg       } while (Tok.isNot(tok::eof));
9697330f729Sjoerg     }
9707330f729Sjoerg     return;
9717330f729Sjoerg   }
9727330f729Sjoerg   llvm::outs() << Output;
9737330f729Sjoerg }
974