xref: /openbsd-src/gnu/llvm/clang/lib/Frontend/FrontendActions.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- FrontendActions.cpp ----------------------------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "clang/Frontend/FrontendActions.h"
10e5dd7070Spatrick #include "clang/AST/ASTConsumer.h"
11*12c85518Srobert #include "clang/AST/Decl.h"
12e5dd7070Spatrick #include "clang/Basic/FileManager.h"
13e5dd7070Spatrick #include "clang/Basic/LangStandard.h"
14*12c85518Srobert #include "clang/Basic/Module.h"
15*12c85518Srobert #include "clang/Basic/TargetInfo.h"
16e5dd7070Spatrick #include "clang/Frontend/ASTConsumers.h"
17e5dd7070Spatrick #include "clang/Frontend/CompilerInstance.h"
18e5dd7070Spatrick #include "clang/Frontend/FrontendDiagnostic.h"
19e5dd7070Spatrick #include "clang/Frontend/MultiplexConsumer.h"
20e5dd7070Spatrick #include "clang/Frontend/Utils.h"
21*12c85518Srobert #include "clang/Lex/DependencyDirectivesScanner.h"
22e5dd7070Spatrick #include "clang/Lex/HeaderSearch.h"
23e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
24e5dd7070Spatrick #include "clang/Lex/PreprocessorOptions.h"
25e5dd7070Spatrick #include "clang/Sema/TemplateInstCallback.h"
26e5dd7070Spatrick #include "clang/Serialization/ASTReader.h"
27e5dd7070Spatrick #include "clang/Serialization/ASTWriter.h"
28*12c85518Srobert #include "clang/Serialization/ModuleFile.h"
29*12c85518Srobert #include "llvm/Support/ErrorHandling.h"
30e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
31e5dd7070Spatrick #include "llvm/Support/MemoryBuffer.h"
32e5dd7070Spatrick #include "llvm/Support/Path.h"
33e5dd7070Spatrick #include "llvm/Support/YAMLTraits.h"
34e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
35e5dd7070Spatrick #include <memory>
36*12c85518Srobert #include <optional>
37e5dd7070Spatrick #include <system_error>
38e5dd7070Spatrick 
39e5dd7070Spatrick using namespace clang;
40e5dd7070Spatrick 
41e5dd7070Spatrick namespace {
GetCodeCompletionConsumer(CompilerInstance & CI)42e5dd7070Spatrick CodeCompleteConsumer *GetCodeCompletionConsumer(CompilerInstance &CI) {
43e5dd7070Spatrick   return CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer()
44e5dd7070Spatrick                                         : nullptr;
45e5dd7070Spatrick }
46e5dd7070Spatrick 
EnsureSemaIsCreated(CompilerInstance & CI,FrontendAction & Action)47e5dd7070Spatrick void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) {
48e5dd7070Spatrick   if (Action.hasCodeCompletionSupport() &&
49e5dd7070Spatrick       !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
50e5dd7070Spatrick     CI.createCodeCompletionConsumer();
51e5dd7070Spatrick 
52e5dd7070Spatrick   if (!CI.hasSema())
53e5dd7070Spatrick     CI.createSema(Action.getTranslationUnitKind(),
54e5dd7070Spatrick                   GetCodeCompletionConsumer(CI));
55e5dd7070Spatrick }
56e5dd7070Spatrick } // namespace
57e5dd7070Spatrick 
58e5dd7070Spatrick //===----------------------------------------------------------------------===//
59e5dd7070Spatrick // Custom Actions
60e5dd7070Spatrick //===----------------------------------------------------------------------===//
61e5dd7070Spatrick 
62e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)63e5dd7070Spatrick InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
64e5dd7070Spatrick   return std::make_unique<ASTConsumer>();
65e5dd7070Spatrick }
66e5dd7070Spatrick 
ExecuteAction()67e5dd7070Spatrick void InitOnlyAction::ExecuteAction() {
68e5dd7070Spatrick }
69e5dd7070Spatrick 
70a9ac8606Spatrick // Basically PreprocessOnlyAction::ExecuteAction.
ExecuteAction()71a9ac8606Spatrick void ReadPCHAndPreprocessAction::ExecuteAction() {
72a9ac8606Spatrick   Preprocessor &PP = getCompilerInstance().getPreprocessor();
73a9ac8606Spatrick 
74a9ac8606Spatrick   // Ignore unknown pragmas.
75a9ac8606Spatrick   PP.IgnorePragmas();
76a9ac8606Spatrick 
77a9ac8606Spatrick   Token Tok;
78a9ac8606Spatrick   // Start parsing the specified input file.
79a9ac8606Spatrick   PP.EnterMainSourceFile();
80a9ac8606Spatrick   do {
81a9ac8606Spatrick     PP.Lex(Tok);
82a9ac8606Spatrick   } while (Tok.isNot(tok::eof));
83a9ac8606Spatrick }
84a9ac8606Spatrick 
85a9ac8606Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)86a9ac8606Spatrick ReadPCHAndPreprocessAction::CreateASTConsumer(CompilerInstance &CI,
87a9ac8606Spatrick                                               StringRef InFile) {
88a9ac8606Spatrick   return std::make_unique<ASTConsumer>();
89a9ac8606Spatrick }
90a9ac8606Spatrick 
91e5dd7070Spatrick //===----------------------------------------------------------------------===//
92e5dd7070Spatrick // AST Consumer Actions
93e5dd7070Spatrick //===----------------------------------------------------------------------===//
94e5dd7070Spatrick 
95e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)96e5dd7070Spatrick ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
97e5dd7070Spatrick   if (std::unique_ptr<raw_ostream> OS =
98e5dd7070Spatrick           CI.createDefaultOutputFile(false, InFile))
99e5dd7070Spatrick     return CreateASTPrinter(std::move(OS), CI.getFrontendOpts().ASTDumpFilter);
100e5dd7070Spatrick   return nullptr;
101e5dd7070Spatrick }
102e5dd7070Spatrick 
103e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)104e5dd7070Spatrick ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
105e5dd7070Spatrick   const FrontendOptions &Opts = CI.getFrontendOpts();
106e5dd7070Spatrick   return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter,
107e5dd7070Spatrick                          Opts.ASTDumpDecls, Opts.ASTDumpAll,
108ec727ea7Spatrick                          Opts.ASTDumpLookups, Opts.ASTDumpDeclTypes,
109ec727ea7Spatrick                          Opts.ASTDumpFormat);
110e5dd7070Spatrick }
111e5dd7070Spatrick 
112e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)113e5dd7070Spatrick ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
114e5dd7070Spatrick   return CreateASTDeclNodeLister();
115e5dd7070Spatrick }
116e5dd7070Spatrick 
117e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)118e5dd7070Spatrick ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
119e5dd7070Spatrick   return CreateASTViewer();
120e5dd7070Spatrick }
121e5dd7070Spatrick 
122e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)123e5dd7070Spatrick GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
124e5dd7070Spatrick   std::string Sysroot;
125e5dd7070Spatrick   if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot))
126e5dd7070Spatrick     return nullptr;
127e5dd7070Spatrick 
128e5dd7070Spatrick   std::string OutputFile;
129e5dd7070Spatrick   std::unique_ptr<raw_pwrite_stream> OS =
130e5dd7070Spatrick       CreateOutputFile(CI, InFile, /*ref*/ OutputFile);
131e5dd7070Spatrick   if (!OS)
132e5dd7070Spatrick     return nullptr;
133e5dd7070Spatrick 
134e5dd7070Spatrick   if (!CI.getFrontendOpts().RelocatablePCH)
135e5dd7070Spatrick     Sysroot.clear();
136e5dd7070Spatrick 
137e5dd7070Spatrick   const auto &FrontendOpts = CI.getFrontendOpts();
138e5dd7070Spatrick   auto Buffer = std::make_shared<PCHBuffer>();
139e5dd7070Spatrick   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
140e5dd7070Spatrick   Consumers.push_back(std::make_unique<PCHGenerator>(
141e5dd7070Spatrick       CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
142e5dd7070Spatrick       FrontendOpts.ModuleFileExtensions,
143e5dd7070Spatrick       CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
144e5dd7070Spatrick       FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH));
145e5dd7070Spatrick   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
146ec727ea7Spatrick       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
147e5dd7070Spatrick 
148e5dd7070Spatrick   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
149e5dd7070Spatrick }
150e5dd7070Spatrick 
ComputeASTConsumerArguments(CompilerInstance & CI,std::string & Sysroot)151e5dd7070Spatrick bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
152e5dd7070Spatrick                                                     std::string &Sysroot) {
153e5dd7070Spatrick   Sysroot = CI.getHeaderSearchOpts().Sysroot;
154e5dd7070Spatrick   if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
155e5dd7070Spatrick     CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot);
156e5dd7070Spatrick     return false;
157e5dd7070Spatrick   }
158e5dd7070Spatrick 
159e5dd7070Spatrick   return true;
160e5dd7070Spatrick }
161e5dd7070Spatrick 
162e5dd7070Spatrick std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile,std::string & OutputFile)163e5dd7070Spatrick GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile,
164e5dd7070Spatrick                                     std::string &OutputFile) {
165a9ac8606Spatrick   // Because this is exposed via libclang we must disable RemoveFileOnSignal.
166a9ac8606Spatrick   std::unique_ptr<raw_pwrite_stream> OS = CI.createDefaultOutputFile(
167a9ac8606Spatrick       /*Binary=*/true, InFile, /*Extension=*/"", /*RemoveFileOnSignal=*/false);
168e5dd7070Spatrick   if (!OS)
169e5dd7070Spatrick     return nullptr;
170e5dd7070Spatrick 
171e5dd7070Spatrick   OutputFile = CI.getFrontendOpts().OutputFile;
172e5dd7070Spatrick   return OS;
173e5dd7070Spatrick }
174e5dd7070Spatrick 
shouldEraseOutputFiles()175e5dd7070Spatrick bool GeneratePCHAction::shouldEraseOutputFiles() {
176e5dd7070Spatrick   if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
177e5dd7070Spatrick     return false;
178e5dd7070Spatrick   return ASTFrontendAction::shouldEraseOutputFiles();
179e5dd7070Spatrick }
180e5dd7070Spatrick 
BeginSourceFileAction(CompilerInstance & CI)181e5dd7070Spatrick bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
182e5dd7070Spatrick   CI.getLangOpts().CompilingPCH = true;
183e5dd7070Spatrick   return true;
184e5dd7070Spatrick }
185e5dd7070Spatrick 
186e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)187e5dd7070Spatrick GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
188e5dd7070Spatrick                                         StringRef InFile) {
189e5dd7070Spatrick   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
190e5dd7070Spatrick   if (!OS)
191e5dd7070Spatrick     return nullptr;
192e5dd7070Spatrick 
193e5dd7070Spatrick   std::string OutputFile = CI.getFrontendOpts().OutputFile;
194e5dd7070Spatrick   std::string Sysroot;
195e5dd7070Spatrick 
196e5dd7070Spatrick   auto Buffer = std::make_shared<PCHBuffer>();
197e5dd7070Spatrick   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
198e5dd7070Spatrick 
199e5dd7070Spatrick   Consumers.push_back(std::make_unique<PCHGenerator>(
200e5dd7070Spatrick       CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
201e5dd7070Spatrick       CI.getFrontendOpts().ModuleFileExtensions,
202a9ac8606Spatrick       /*AllowASTWithErrors=*/
203a9ac8606Spatrick       +CI.getFrontendOpts().AllowPCMWithCompilerErrors,
204e5dd7070Spatrick       /*IncludeTimestamps=*/
205e5dd7070Spatrick       +CI.getFrontendOpts().BuildingImplicitModule,
206e5dd7070Spatrick       /*ShouldCacheASTInMemory=*/
207e5dd7070Spatrick       +CI.getFrontendOpts().BuildingImplicitModule));
208e5dd7070Spatrick   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
209ec727ea7Spatrick       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
210e5dd7070Spatrick   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
211e5dd7070Spatrick }
212e5dd7070Spatrick 
shouldEraseOutputFiles()213a9ac8606Spatrick bool GenerateModuleAction::shouldEraseOutputFiles() {
214a9ac8606Spatrick   return !getCompilerInstance().getFrontendOpts().AllowPCMWithCompilerErrors &&
215a9ac8606Spatrick          ASTFrontendAction::shouldEraseOutputFiles();
216a9ac8606Spatrick }
217a9ac8606Spatrick 
BeginSourceFileAction(CompilerInstance & CI)218e5dd7070Spatrick bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
219e5dd7070Spatrick     CompilerInstance &CI) {
220e5dd7070Spatrick   if (!CI.getLangOpts().Modules) {
221e5dd7070Spatrick     CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules);
222e5dd7070Spatrick     return false;
223e5dd7070Spatrick   }
224e5dd7070Spatrick 
225e5dd7070Spatrick   return GenerateModuleAction::BeginSourceFileAction(CI);
226e5dd7070Spatrick }
227e5dd7070Spatrick 
228e5dd7070Spatrick std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)229e5dd7070Spatrick GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
230e5dd7070Spatrick                                                     StringRef InFile) {
231e5dd7070Spatrick   // If no output file was provided, figure out where this module would go
232e5dd7070Spatrick   // in the module cache.
233e5dd7070Spatrick   if (CI.getFrontendOpts().OutputFile.empty()) {
234e5dd7070Spatrick     StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
235e5dd7070Spatrick     if (ModuleMapFile.empty())
236e5dd7070Spatrick       ModuleMapFile = InFile;
237e5dd7070Spatrick 
238e5dd7070Spatrick     HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
239e5dd7070Spatrick     CI.getFrontendOpts().OutputFile =
240e5dd7070Spatrick         HS.getCachedModuleFileName(CI.getLangOpts().CurrentModule,
241e5dd7070Spatrick                                    ModuleMapFile);
242e5dd7070Spatrick   }
243e5dd7070Spatrick 
244a9ac8606Spatrick   // Because this is exposed via libclang we must disable RemoveFileOnSignal.
245a9ac8606Spatrick   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, /*Extension=*/"",
246a9ac8606Spatrick                                     /*RemoveFileOnSignal=*/false,
247a9ac8606Spatrick                                     /*CreateMissingDirectories=*/true,
248a9ac8606Spatrick                                     /*ForceUseTemporary=*/true);
249e5dd7070Spatrick }
250e5dd7070Spatrick 
BeginSourceFileAction(CompilerInstance & CI)251e5dd7070Spatrick bool GenerateModuleInterfaceAction::BeginSourceFileAction(
252e5dd7070Spatrick     CompilerInstance &CI) {
253e5dd7070Spatrick   if (!CI.getLangOpts().ModulesTS && !CI.getLangOpts().CPlusPlusModules) {
254e5dd7070Spatrick     CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
255e5dd7070Spatrick     return false;
256e5dd7070Spatrick   }
257e5dd7070Spatrick 
258e5dd7070Spatrick   CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
259e5dd7070Spatrick 
260e5dd7070Spatrick   return GenerateModuleAction::BeginSourceFileAction(CI);
261e5dd7070Spatrick }
262e5dd7070Spatrick 
263e5dd7070Spatrick std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)264e5dd7070Spatrick GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
265e5dd7070Spatrick                                                 StringRef InFile) {
266e5dd7070Spatrick   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
267e5dd7070Spatrick }
268e5dd7070Spatrick 
BeginSourceFileAction(CompilerInstance & CI)269*12c85518Srobert bool GenerateHeaderUnitAction::BeginSourceFileAction(CompilerInstance &CI) {
270*12c85518Srobert   if (!CI.getLangOpts().CPlusPlusModules) {
271*12c85518Srobert     CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
272e5dd7070Spatrick     return false;
273e5dd7070Spatrick   }
274*12c85518Srobert   CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderUnit);
275e5dd7070Spatrick   return GenerateModuleAction::BeginSourceFileAction(CI);
276e5dd7070Spatrick }
277e5dd7070Spatrick 
278e5dd7070Spatrick std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance & CI,StringRef InFile)279*12c85518Srobert GenerateHeaderUnitAction::CreateOutputFile(CompilerInstance &CI,
280e5dd7070Spatrick                                            StringRef InFile) {
281e5dd7070Spatrick   return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
282e5dd7070Spatrick }
283e5dd7070Spatrick 
~SyntaxOnlyAction()284e5dd7070Spatrick SyntaxOnlyAction::~SyntaxOnlyAction() {
285e5dd7070Spatrick }
286e5dd7070Spatrick 
287e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)288e5dd7070Spatrick SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
289e5dd7070Spatrick   return std::make_unique<ASTConsumer>();
290e5dd7070Spatrick }
291e5dd7070Spatrick 
292e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)293e5dd7070Spatrick DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
294e5dd7070Spatrick                                         StringRef InFile) {
295e5dd7070Spatrick   return std::make_unique<ASTConsumer>();
296e5dd7070Spatrick }
297e5dd7070Spatrick 
298e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)299e5dd7070Spatrick VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
300e5dd7070Spatrick   return std::make_unique<ASTConsumer>();
301e5dd7070Spatrick }
302e5dd7070Spatrick 
ExecuteAction()303e5dd7070Spatrick void VerifyPCHAction::ExecuteAction() {
304e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
305e5dd7070Spatrick   bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
306e5dd7070Spatrick   const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
307e5dd7070Spatrick   std::unique_ptr<ASTReader> Reader(new ASTReader(
308e5dd7070Spatrick       CI.getPreprocessor(), CI.getModuleCache(), &CI.getASTContext(),
309e5dd7070Spatrick       CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions,
310e5dd7070Spatrick       Sysroot.empty() ? "" : Sysroot.c_str(),
311a9ac8606Spatrick       DisableValidationForModuleKind::None,
312a9ac8606Spatrick       /*AllowASTWithCompilerErrors*/ false,
313e5dd7070Spatrick       /*AllowConfigurationMismatch*/ true,
314e5dd7070Spatrick       /*ValidateSystemInputs*/ true));
315e5dd7070Spatrick 
316e5dd7070Spatrick   Reader->ReadAST(getCurrentFile(),
317e5dd7070Spatrick                   Preamble ? serialization::MK_Preamble
318e5dd7070Spatrick                            : serialization::MK_PCH,
319e5dd7070Spatrick                   SourceLocation(),
320e5dd7070Spatrick                   ASTReader::ARR_ConfigurationMismatch);
321e5dd7070Spatrick }
322e5dd7070Spatrick 
323e5dd7070Spatrick namespace {
324e5dd7070Spatrick struct TemplightEntry {
325e5dd7070Spatrick   std::string Name;
326e5dd7070Spatrick   std::string Kind;
327e5dd7070Spatrick   std::string Event;
328e5dd7070Spatrick   std::string DefinitionLocation;
329e5dd7070Spatrick   std::string PointOfInstantiation;
330e5dd7070Spatrick };
331e5dd7070Spatrick } // namespace
332e5dd7070Spatrick 
333e5dd7070Spatrick namespace llvm {
334e5dd7070Spatrick namespace yaml {
335e5dd7070Spatrick template <> struct MappingTraits<TemplightEntry> {
mappingllvm::yaml::MappingTraits336e5dd7070Spatrick   static void mapping(IO &io, TemplightEntry &fields) {
337e5dd7070Spatrick     io.mapRequired("name", fields.Name);
338e5dd7070Spatrick     io.mapRequired("kind", fields.Kind);
339e5dd7070Spatrick     io.mapRequired("event", fields.Event);
340e5dd7070Spatrick     io.mapRequired("orig", fields.DefinitionLocation);
341e5dd7070Spatrick     io.mapRequired("poi", fields.PointOfInstantiation);
342e5dd7070Spatrick   }
343e5dd7070Spatrick };
344e5dd7070Spatrick } // namespace yaml
345e5dd7070Spatrick } // namespace llvm
346e5dd7070Spatrick 
347e5dd7070Spatrick namespace {
348e5dd7070Spatrick class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
349e5dd7070Spatrick   using CodeSynthesisContext = Sema::CodeSynthesisContext;
350e5dd7070Spatrick 
351e5dd7070Spatrick public:
initialize(const Sema &)352e5dd7070Spatrick   void initialize(const Sema &) override {}
353e5dd7070Spatrick 
finalize(const Sema &)354e5dd7070Spatrick   void finalize(const Sema &) override {}
355e5dd7070Spatrick 
atTemplateBegin(const Sema & TheSema,const CodeSynthesisContext & Inst)356e5dd7070Spatrick   void atTemplateBegin(const Sema &TheSema,
357e5dd7070Spatrick                        const CodeSynthesisContext &Inst) override {
358e5dd7070Spatrick     displayTemplightEntry<true>(llvm::outs(), TheSema, Inst);
359e5dd7070Spatrick   }
360e5dd7070Spatrick 
atTemplateEnd(const Sema & TheSema,const CodeSynthesisContext & Inst)361e5dd7070Spatrick   void atTemplateEnd(const Sema &TheSema,
362e5dd7070Spatrick                      const CodeSynthesisContext &Inst) override {
363e5dd7070Spatrick     displayTemplightEntry<false>(llvm::outs(), TheSema, Inst);
364e5dd7070Spatrick   }
365e5dd7070Spatrick 
366e5dd7070Spatrick private:
toString(CodeSynthesisContext::SynthesisKind Kind)367e5dd7070Spatrick   static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
368e5dd7070Spatrick     switch (Kind) {
369e5dd7070Spatrick     case CodeSynthesisContext::TemplateInstantiation:
370e5dd7070Spatrick       return "TemplateInstantiation";
371e5dd7070Spatrick     case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
372e5dd7070Spatrick       return "DefaultTemplateArgumentInstantiation";
373e5dd7070Spatrick     case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
374e5dd7070Spatrick       return "DefaultFunctionArgumentInstantiation";
375e5dd7070Spatrick     case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
376e5dd7070Spatrick       return "ExplicitTemplateArgumentSubstitution";
377e5dd7070Spatrick     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
378e5dd7070Spatrick       return "DeducedTemplateArgumentSubstitution";
379e5dd7070Spatrick     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
380e5dd7070Spatrick       return "PriorTemplateArgumentSubstitution";
381e5dd7070Spatrick     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
382e5dd7070Spatrick       return "DefaultTemplateArgumentChecking";
383e5dd7070Spatrick     case CodeSynthesisContext::ExceptionSpecEvaluation:
384e5dd7070Spatrick       return "ExceptionSpecEvaluation";
385e5dd7070Spatrick     case CodeSynthesisContext::ExceptionSpecInstantiation:
386e5dd7070Spatrick       return "ExceptionSpecInstantiation";
387e5dd7070Spatrick     case CodeSynthesisContext::DeclaringSpecialMember:
388e5dd7070Spatrick       return "DeclaringSpecialMember";
389e5dd7070Spatrick     case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
390e5dd7070Spatrick       return "DeclaringImplicitEqualityComparison";
391e5dd7070Spatrick     case CodeSynthesisContext::DefiningSynthesizedFunction:
392e5dd7070Spatrick       return "DefiningSynthesizedFunction";
393e5dd7070Spatrick     case CodeSynthesisContext::RewritingOperatorAsSpaceship:
394e5dd7070Spatrick       return "RewritingOperatorAsSpaceship";
395e5dd7070Spatrick     case CodeSynthesisContext::Memoization:
396e5dd7070Spatrick       return "Memoization";
397e5dd7070Spatrick     case CodeSynthesisContext::ConstraintsCheck:
398e5dd7070Spatrick       return "ConstraintsCheck";
399e5dd7070Spatrick     case CodeSynthesisContext::ConstraintSubstitution:
400e5dd7070Spatrick       return "ConstraintSubstitution";
401e5dd7070Spatrick     case CodeSynthesisContext::ConstraintNormalization:
402e5dd7070Spatrick       return "ConstraintNormalization";
403*12c85518Srobert     case CodeSynthesisContext::RequirementParameterInstantiation:
404*12c85518Srobert       return "RequirementParameterInstantiation";
405e5dd7070Spatrick     case CodeSynthesisContext::ParameterMappingSubstitution:
406e5dd7070Spatrick       return "ParameterMappingSubstitution";
407e5dd7070Spatrick     case CodeSynthesisContext::RequirementInstantiation:
408e5dd7070Spatrick       return "RequirementInstantiation";
409e5dd7070Spatrick     case CodeSynthesisContext::NestedRequirementConstraintsCheck:
410e5dd7070Spatrick       return "NestedRequirementConstraintsCheck";
411ec727ea7Spatrick     case CodeSynthesisContext::InitializingStructuredBinding:
412ec727ea7Spatrick       return "InitializingStructuredBinding";
413ec727ea7Spatrick     case CodeSynthesisContext::MarkingClassDllexported:
414ec727ea7Spatrick       return "MarkingClassDllexported";
415*12c85518Srobert     case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
416*12c85518Srobert       return "BuildingBuiltinDumpStructCall";
417e5dd7070Spatrick     }
418e5dd7070Spatrick     return "";
419e5dd7070Spatrick   }
420e5dd7070Spatrick 
421e5dd7070Spatrick   template <bool BeginInstantiation>
displayTemplightEntry(llvm::raw_ostream & Out,const Sema & TheSema,const CodeSynthesisContext & Inst)422e5dd7070Spatrick   static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema,
423e5dd7070Spatrick                                     const CodeSynthesisContext &Inst) {
424e5dd7070Spatrick     std::string YAML;
425e5dd7070Spatrick     {
426e5dd7070Spatrick       llvm::raw_string_ostream OS(YAML);
427e5dd7070Spatrick       llvm::yaml::Output YO(OS);
428e5dd7070Spatrick       TemplightEntry Entry =
429e5dd7070Spatrick           getTemplightEntry<BeginInstantiation>(TheSema, Inst);
430e5dd7070Spatrick       llvm::yaml::EmptyContext Context;
431e5dd7070Spatrick       llvm::yaml::yamlize(YO, Entry, true, Context);
432e5dd7070Spatrick     }
433e5dd7070Spatrick     Out << "---" << YAML << "\n";
434e5dd7070Spatrick   }
435e5dd7070Spatrick 
printEntryName(const Sema & TheSema,const Decl * Entity,llvm::raw_string_ostream & OS)436*12c85518Srobert   static void printEntryName(const Sema &TheSema, const Decl *Entity,
437*12c85518Srobert                              llvm::raw_string_ostream &OS) {
438*12c85518Srobert     auto *NamedTemplate = cast<NamedDecl>(Entity);
439*12c85518Srobert 
440*12c85518Srobert     PrintingPolicy Policy = TheSema.Context.getPrintingPolicy();
441*12c85518Srobert     // FIXME: Also ask for FullyQualifiedNames?
442*12c85518Srobert     Policy.SuppressDefaultTemplateArgs = false;
443*12c85518Srobert     NamedTemplate->getNameForDiagnostic(OS, Policy, true);
444*12c85518Srobert 
445*12c85518Srobert     if (!OS.str().empty())
446*12c85518Srobert       return;
447*12c85518Srobert 
448*12c85518Srobert     Decl *Ctx = Decl::castFromDeclContext(NamedTemplate->getDeclContext());
449*12c85518Srobert     NamedDecl *NamedCtx = dyn_cast_or_null<NamedDecl>(Ctx);
450*12c85518Srobert 
451*12c85518Srobert     if (const auto *Decl = dyn_cast<TagDecl>(NamedTemplate)) {
452*12c85518Srobert       if (const auto *R = dyn_cast<RecordDecl>(Decl)) {
453*12c85518Srobert         if (R->isLambda()) {
454*12c85518Srobert           OS << "lambda at ";
455*12c85518Srobert           Decl->getLocation().print(OS, TheSema.getSourceManager());
456*12c85518Srobert           return;
457*12c85518Srobert         }
458*12c85518Srobert       }
459*12c85518Srobert       OS << "unnamed " << Decl->getKindName();
460*12c85518Srobert       return;
461*12c85518Srobert     }
462*12c85518Srobert 
463*12c85518Srobert     if (const auto *Decl = dyn_cast<ParmVarDecl>(NamedTemplate)) {
464*12c85518Srobert       OS << "unnamed function parameter " << Decl->getFunctionScopeIndex()
465*12c85518Srobert          << " ";
466*12c85518Srobert       if (Decl->getFunctionScopeDepth() > 0)
467*12c85518Srobert         OS << "(at depth " << Decl->getFunctionScopeDepth() << ") ";
468*12c85518Srobert       OS << "of ";
469*12c85518Srobert       NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
470*12c85518Srobert       return;
471*12c85518Srobert     }
472*12c85518Srobert 
473*12c85518Srobert     if (const auto *Decl = dyn_cast<TemplateTypeParmDecl>(NamedTemplate)) {
474*12c85518Srobert       if (const Type *Ty = Decl->getTypeForDecl()) {
475*12c85518Srobert         if (const auto *TTPT = dyn_cast_or_null<TemplateTypeParmType>(Ty)) {
476*12c85518Srobert           OS << "unnamed template type parameter " << TTPT->getIndex() << " ";
477*12c85518Srobert           if (TTPT->getDepth() > 0)
478*12c85518Srobert             OS << "(at depth " << TTPT->getDepth() << ") ";
479*12c85518Srobert           OS << "of ";
480*12c85518Srobert           NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
481*12c85518Srobert           return;
482*12c85518Srobert         }
483*12c85518Srobert       }
484*12c85518Srobert     }
485*12c85518Srobert 
486*12c85518Srobert     if (const auto *Decl = dyn_cast<NonTypeTemplateParmDecl>(NamedTemplate)) {
487*12c85518Srobert       OS << "unnamed template non-type parameter " << Decl->getIndex() << " ";
488*12c85518Srobert       if (Decl->getDepth() > 0)
489*12c85518Srobert         OS << "(at depth " << Decl->getDepth() << ") ";
490*12c85518Srobert       OS << "of ";
491*12c85518Srobert       NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
492*12c85518Srobert       return;
493*12c85518Srobert     }
494*12c85518Srobert 
495*12c85518Srobert     if (const auto *Decl = dyn_cast<TemplateTemplateParmDecl>(NamedTemplate)) {
496*12c85518Srobert       OS << "unnamed template template parameter " << Decl->getIndex() << " ";
497*12c85518Srobert       if (Decl->getDepth() > 0)
498*12c85518Srobert         OS << "(at depth " << Decl->getDepth() << ") ";
499*12c85518Srobert       OS << "of ";
500*12c85518Srobert       NamedCtx->getNameForDiagnostic(OS, TheSema.getLangOpts(), true);
501*12c85518Srobert       return;
502*12c85518Srobert     }
503*12c85518Srobert 
504*12c85518Srobert     llvm_unreachable("Failed to retrieve a name for this entry!");
505*12c85518Srobert     OS << "unnamed identifier";
506*12c85518Srobert   }
507*12c85518Srobert 
508e5dd7070Spatrick   template <bool BeginInstantiation>
getTemplightEntry(const Sema & TheSema,const CodeSynthesisContext & Inst)509e5dd7070Spatrick   static TemplightEntry getTemplightEntry(const Sema &TheSema,
510e5dd7070Spatrick                                           const CodeSynthesisContext &Inst) {
511e5dd7070Spatrick     TemplightEntry Entry;
512e5dd7070Spatrick     Entry.Kind = toString(Inst.Kind);
513e5dd7070Spatrick     Entry.Event = BeginInstantiation ? "Begin" : "End";
514e5dd7070Spatrick     llvm::raw_string_ostream OS(Entry.Name);
515*12c85518Srobert     printEntryName(TheSema, Inst.Entity, OS);
516e5dd7070Spatrick     const PresumedLoc DefLoc =
517e5dd7070Spatrick         TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation());
518e5dd7070Spatrick     if (!DefLoc.isInvalid())
519e5dd7070Spatrick       Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" +
520e5dd7070Spatrick                                  std::to_string(DefLoc.getLine()) + ":" +
521e5dd7070Spatrick                                  std::to_string(DefLoc.getColumn());
522e5dd7070Spatrick     const PresumedLoc PoiLoc =
523e5dd7070Spatrick         TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation);
524e5dd7070Spatrick     if (!PoiLoc.isInvalid()) {
525e5dd7070Spatrick       Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" +
526e5dd7070Spatrick                                    std::to_string(PoiLoc.getLine()) + ":" +
527e5dd7070Spatrick                                    std::to_string(PoiLoc.getColumn());
528e5dd7070Spatrick     }
529e5dd7070Spatrick     return Entry;
530e5dd7070Spatrick   }
531e5dd7070Spatrick };
532e5dd7070Spatrick } // namespace
533e5dd7070Spatrick 
534e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)535e5dd7070Spatrick TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
536e5dd7070Spatrick   return std::make_unique<ASTConsumer>();
537e5dd7070Spatrick }
538e5dd7070Spatrick 
ExecuteAction()539e5dd7070Spatrick void TemplightDumpAction::ExecuteAction() {
540e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
541e5dd7070Spatrick 
542e5dd7070Spatrick   // This part is normally done by ASTFrontEndAction, but needs to happen
543e5dd7070Spatrick   // before Templight observers can be created
544e5dd7070Spatrick   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
545e5dd7070Spatrick   // here so the source manager would be initialized.
546e5dd7070Spatrick   EnsureSemaIsCreated(CI, *this);
547e5dd7070Spatrick 
548e5dd7070Spatrick   CI.getSema().TemplateInstCallbacks.push_back(
549e5dd7070Spatrick       std::make_unique<DefaultTemplateInstCallback>());
550e5dd7070Spatrick   ASTFrontendAction::ExecuteAction();
551e5dd7070Spatrick }
552e5dd7070Spatrick 
553e5dd7070Spatrick namespace {
554e5dd7070Spatrick   /// AST reader listener that dumps module information for a module
555e5dd7070Spatrick   /// file.
556e5dd7070Spatrick   class DumpModuleInfoListener : public ASTReaderListener {
557e5dd7070Spatrick     llvm::raw_ostream &Out;
558e5dd7070Spatrick 
559e5dd7070Spatrick   public:
DumpModuleInfoListener(llvm::raw_ostream & Out)560e5dd7070Spatrick     DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { }
561e5dd7070Spatrick 
562e5dd7070Spatrick #define DUMP_BOOLEAN(Value, Text)                       \
563e5dd7070Spatrick     Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
564e5dd7070Spatrick 
ReadFullVersionInformation(StringRef FullVersion)565e5dd7070Spatrick     bool ReadFullVersionInformation(StringRef FullVersion) override {
566e5dd7070Spatrick       Out.indent(2)
567e5dd7070Spatrick         << "Generated by "
568e5dd7070Spatrick         << (FullVersion == getClangFullRepositoryVersion()? "this"
569e5dd7070Spatrick                                                           : "a different")
570e5dd7070Spatrick         << " Clang: " << FullVersion << "\n";
571e5dd7070Spatrick       return ASTReaderListener::ReadFullVersionInformation(FullVersion);
572e5dd7070Spatrick     }
573e5dd7070Spatrick 
ReadModuleName(StringRef ModuleName)574e5dd7070Spatrick     void ReadModuleName(StringRef ModuleName) override {
575e5dd7070Spatrick       Out.indent(2) << "Module name: " << ModuleName << "\n";
576e5dd7070Spatrick     }
ReadModuleMapFile(StringRef ModuleMapPath)577e5dd7070Spatrick     void ReadModuleMapFile(StringRef ModuleMapPath) override {
578e5dd7070Spatrick       Out.indent(2) << "Module map file: " << ModuleMapPath << "\n";
579e5dd7070Spatrick     }
580e5dd7070Spatrick 
ReadLanguageOptions(const LangOptions & LangOpts,bool Complain,bool AllowCompatibleDifferences)581e5dd7070Spatrick     bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
582e5dd7070Spatrick                              bool AllowCompatibleDifferences) override {
583e5dd7070Spatrick       Out.indent(2) << "Language options:\n";
584e5dd7070Spatrick #define LANGOPT(Name, Bits, Default, Description) \
585e5dd7070Spatrick       DUMP_BOOLEAN(LangOpts.Name, Description);
586e5dd7070Spatrick #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
587e5dd7070Spatrick       Out.indent(4) << Description << ": "                   \
588e5dd7070Spatrick                     << static_cast<unsigned>(LangOpts.get##Name()) << "\n";
589e5dd7070Spatrick #define VALUE_LANGOPT(Name, Bits, Default, Description) \
590e5dd7070Spatrick       Out.indent(4) << Description << ": " << LangOpts.Name << "\n";
591e5dd7070Spatrick #define BENIGN_LANGOPT(Name, Bits, Default, Description)
592e5dd7070Spatrick #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
593e5dd7070Spatrick #include "clang/Basic/LangOptions.def"
594e5dd7070Spatrick 
595e5dd7070Spatrick       if (!LangOpts.ModuleFeatures.empty()) {
596e5dd7070Spatrick         Out.indent(4) << "Module features:\n";
597e5dd7070Spatrick         for (StringRef Feature : LangOpts.ModuleFeatures)
598e5dd7070Spatrick           Out.indent(6) << Feature << "\n";
599e5dd7070Spatrick       }
600e5dd7070Spatrick 
601e5dd7070Spatrick       return false;
602e5dd7070Spatrick     }
603e5dd7070Spatrick 
ReadTargetOptions(const TargetOptions & TargetOpts,bool Complain,bool AllowCompatibleDifferences)604e5dd7070Spatrick     bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
605e5dd7070Spatrick                            bool AllowCompatibleDifferences) override {
606e5dd7070Spatrick       Out.indent(2) << "Target options:\n";
607e5dd7070Spatrick       Out.indent(4) << "  Triple: " << TargetOpts.Triple << "\n";
608e5dd7070Spatrick       Out.indent(4) << "  CPU: " << TargetOpts.CPU << "\n";
609a9ac8606Spatrick       Out.indent(4) << "  TuneCPU: " << TargetOpts.TuneCPU << "\n";
610e5dd7070Spatrick       Out.indent(4) << "  ABI: " << TargetOpts.ABI << "\n";
611e5dd7070Spatrick 
612e5dd7070Spatrick       if (!TargetOpts.FeaturesAsWritten.empty()) {
613e5dd7070Spatrick         Out.indent(4) << "Target features:\n";
614e5dd7070Spatrick         for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size();
615e5dd7070Spatrick              I != N; ++I) {
616e5dd7070Spatrick           Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n";
617e5dd7070Spatrick         }
618e5dd7070Spatrick       }
619e5dd7070Spatrick 
620e5dd7070Spatrick       return false;
621e5dd7070Spatrick     }
622e5dd7070Spatrick 
ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,bool Complain)623e5dd7070Spatrick     bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
624e5dd7070Spatrick                                bool Complain) override {
625e5dd7070Spatrick       Out.indent(2) << "Diagnostic options:\n";
626e5dd7070Spatrick #define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
627e5dd7070Spatrick #define ENUM_DIAGOPT(Name, Type, Bits, Default) \
628e5dd7070Spatrick       Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
629e5dd7070Spatrick #define VALUE_DIAGOPT(Name, Bits, Default) \
630e5dd7070Spatrick       Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
631e5dd7070Spatrick #include "clang/Basic/DiagnosticOptions.def"
632e5dd7070Spatrick 
633e5dd7070Spatrick       Out.indent(4) << "Diagnostic flags:\n";
634e5dd7070Spatrick       for (const std::string &Warning : DiagOpts->Warnings)
635e5dd7070Spatrick         Out.indent(6) << "-W" << Warning << "\n";
636e5dd7070Spatrick       for (const std::string &Remark : DiagOpts->Remarks)
637e5dd7070Spatrick         Out.indent(6) << "-R" << Remark << "\n";
638e5dd7070Spatrick 
639e5dd7070Spatrick       return false;
640e5dd7070Spatrick     }
641e5dd7070Spatrick 
ReadHeaderSearchOptions(const HeaderSearchOptions & HSOpts,StringRef SpecificModuleCachePath,bool Complain)642e5dd7070Spatrick     bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
643e5dd7070Spatrick                                  StringRef SpecificModuleCachePath,
644e5dd7070Spatrick                                  bool Complain) override {
645e5dd7070Spatrick       Out.indent(2) << "Header search options:\n";
646e5dd7070Spatrick       Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
647e5dd7070Spatrick       Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n";
648e5dd7070Spatrick       Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n";
649e5dd7070Spatrick       DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
650e5dd7070Spatrick                    "Use builtin include directories [-nobuiltininc]");
651e5dd7070Spatrick       DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes,
652e5dd7070Spatrick                    "Use standard system include directories [-nostdinc]");
653e5dd7070Spatrick       DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes,
654e5dd7070Spatrick                    "Use standard C++ include directories [-nostdinc++]");
655e5dd7070Spatrick       DUMP_BOOLEAN(HSOpts.UseLibcxx,
656e5dd7070Spatrick                    "Use libc++ (rather than libstdc++) [-stdlib=]");
657e5dd7070Spatrick       return false;
658e5dd7070Spatrick     }
659e5dd7070Spatrick 
ReadPreprocessorOptions(const PreprocessorOptions & PPOpts,bool Complain,std::string & SuggestedPredefines)660e5dd7070Spatrick     bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
661e5dd7070Spatrick                                  bool Complain,
662e5dd7070Spatrick                                  std::string &SuggestedPredefines) override {
663e5dd7070Spatrick       Out.indent(2) << "Preprocessor options:\n";
664e5dd7070Spatrick       DUMP_BOOLEAN(PPOpts.UsePredefines,
665e5dd7070Spatrick                    "Uses compiler/target-specific predefines [-undef]");
666e5dd7070Spatrick       DUMP_BOOLEAN(PPOpts.DetailedRecord,
667e5dd7070Spatrick                    "Uses detailed preprocessing record (for indexing)");
668e5dd7070Spatrick 
669e5dd7070Spatrick       if (!PPOpts.Macros.empty()) {
670e5dd7070Spatrick         Out.indent(4) << "Predefined macros:\n";
671e5dd7070Spatrick       }
672e5dd7070Spatrick 
673e5dd7070Spatrick       for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
674e5dd7070Spatrick              I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end();
675e5dd7070Spatrick            I != IEnd; ++I) {
676e5dd7070Spatrick         Out.indent(6);
677e5dd7070Spatrick         if (I->second)
678e5dd7070Spatrick           Out << "-U";
679e5dd7070Spatrick         else
680e5dd7070Spatrick           Out << "-D";
681e5dd7070Spatrick         Out << I->first << "\n";
682e5dd7070Spatrick       }
683e5dd7070Spatrick       return false;
684e5dd7070Spatrick     }
685e5dd7070Spatrick 
686e5dd7070Spatrick     /// Indicates that a particular module file extension has been read.
readModuleFileExtension(const ModuleFileExtensionMetadata & Metadata)687e5dd7070Spatrick     void readModuleFileExtension(
688e5dd7070Spatrick            const ModuleFileExtensionMetadata &Metadata) override {
689e5dd7070Spatrick       Out.indent(2) << "Module file extension '"
690e5dd7070Spatrick                     << Metadata.BlockName << "' " << Metadata.MajorVersion
691e5dd7070Spatrick                     << "." << Metadata.MinorVersion;
692e5dd7070Spatrick       if (!Metadata.UserInfo.empty()) {
693e5dd7070Spatrick         Out << ": ";
694e5dd7070Spatrick         Out.write_escaped(Metadata.UserInfo);
695e5dd7070Spatrick       }
696e5dd7070Spatrick 
697e5dd7070Spatrick       Out << "\n";
698e5dd7070Spatrick     }
699e5dd7070Spatrick 
700e5dd7070Spatrick     /// Tells the \c ASTReaderListener that we want to receive the
701e5dd7070Spatrick     /// input files of the AST file via \c visitInputFile.
needsInputFileVisitation()702e5dd7070Spatrick     bool needsInputFileVisitation() override { return true; }
703e5dd7070Spatrick 
704e5dd7070Spatrick     /// Tells the \c ASTReaderListener that we want to receive the
705e5dd7070Spatrick     /// input files of the AST file via \c visitInputFile.
needsSystemInputFileVisitation()706e5dd7070Spatrick     bool needsSystemInputFileVisitation() override { return true; }
707e5dd7070Spatrick 
708e5dd7070Spatrick     /// Indicates that the AST file contains particular input file.
709e5dd7070Spatrick     ///
710e5dd7070Spatrick     /// \returns true to continue receiving the next input file, false to stop.
visitInputFile(StringRef Filename,bool isSystem,bool isOverridden,bool isExplicitModule)711e5dd7070Spatrick     bool visitInputFile(StringRef Filename, bool isSystem,
712e5dd7070Spatrick                         bool isOverridden, bool isExplicitModule) override {
713e5dd7070Spatrick 
714e5dd7070Spatrick       Out.indent(2) << "Input file: " << Filename;
715e5dd7070Spatrick 
716e5dd7070Spatrick       if (isSystem || isOverridden || isExplicitModule) {
717e5dd7070Spatrick         Out << " [";
718e5dd7070Spatrick         if (isSystem) {
719e5dd7070Spatrick           Out << "System";
720e5dd7070Spatrick           if (isOverridden || isExplicitModule)
721e5dd7070Spatrick             Out << ", ";
722e5dd7070Spatrick         }
723e5dd7070Spatrick         if (isOverridden) {
724e5dd7070Spatrick           Out << "Overridden";
725e5dd7070Spatrick           if (isExplicitModule)
726e5dd7070Spatrick             Out << ", ";
727e5dd7070Spatrick         }
728e5dd7070Spatrick         if (isExplicitModule)
729e5dd7070Spatrick           Out << "ExplicitModule";
730e5dd7070Spatrick 
731e5dd7070Spatrick         Out << "]";
732e5dd7070Spatrick       }
733e5dd7070Spatrick 
734e5dd7070Spatrick       Out << "\n";
735e5dd7070Spatrick 
736e5dd7070Spatrick       return true;
737e5dd7070Spatrick     }
738e5dd7070Spatrick 
739e5dd7070Spatrick     /// Returns true if this \c ASTReaderListener wants to receive the
740e5dd7070Spatrick     /// imports of the AST file via \c visitImport, false otherwise.
needsImportVisitation() const741e5dd7070Spatrick     bool needsImportVisitation() const override { return true; }
742e5dd7070Spatrick 
743e5dd7070Spatrick     /// If needsImportVisitation returns \c true, this is called for each
744e5dd7070Spatrick     /// AST file imported by this AST file.
visitImport(StringRef ModuleName,StringRef Filename)745e5dd7070Spatrick     void visitImport(StringRef ModuleName, StringRef Filename) override {
746e5dd7070Spatrick       Out.indent(2) << "Imports module '" << ModuleName
747e5dd7070Spatrick                     << "': " << Filename.str() << "\n";
748e5dd7070Spatrick     }
749e5dd7070Spatrick #undef DUMP_BOOLEAN
750e5dd7070Spatrick   };
751e5dd7070Spatrick }
752e5dd7070Spatrick 
BeginInvocation(CompilerInstance & CI)753e5dd7070Spatrick bool DumpModuleInfoAction::BeginInvocation(CompilerInstance &CI) {
754e5dd7070Spatrick   // The Object file reader also supports raw ast files and there is no point in
755e5dd7070Spatrick   // being strict about the module file format in -module-file-info mode.
756e5dd7070Spatrick   CI.getHeaderSearchOpts().ModuleFormat = "obj";
757e5dd7070Spatrick   return true;
758e5dd7070Spatrick }
759e5dd7070Spatrick 
ModuleKindName(Module::ModuleKind MK)760*12c85518Srobert static StringRef ModuleKindName(Module::ModuleKind MK) {
761*12c85518Srobert   switch (MK) {
762*12c85518Srobert   case Module::ModuleMapModule:
763*12c85518Srobert     return "Module Map Module";
764*12c85518Srobert   case Module::ModuleInterfaceUnit:
765*12c85518Srobert     return "Interface Unit";
766*12c85518Srobert   case Module::ModulePartitionInterface:
767*12c85518Srobert     return "Partition Interface";
768*12c85518Srobert   case Module::ModulePartitionImplementation:
769*12c85518Srobert     return "Partition Implementation";
770*12c85518Srobert   case Module::ModuleHeaderUnit:
771*12c85518Srobert     return "Header Unit";
772*12c85518Srobert   case Module::GlobalModuleFragment:
773*12c85518Srobert     return "Global Module Fragment";
774*12c85518Srobert   case Module::PrivateModuleFragment:
775*12c85518Srobert     return "Private Module Fragment";
776*12c85518Srobert   }
777*12c85518Srobert   llvm_unreachable("unknown module kind!");
778*12c85518Srobert }
779*12c85518Srobert 
ExecuteAction()780e5dd7070Spatrick void DumpModuleInfoAction::ExecuteAction() {
781*12c85518Srobert   assert(isCurrentFileAST() && "dumping non-AST?");
782e5dd7070Spatrick   // Set up the output file.
783e5dd7070Spatrick   std::unique_ptr<llvm::raw_fd_ostream> OutFile;
784*12c85518Srobert   CompilerInstance &CI = getCompilerInstance();
785*12c85518Srobert   StringRef OutputFileName = CI.getFrontendOpts().OutputFile;
786e5dd7070Spatrick   if (!OutputFileName.empty() && OutputFileName != "-") {
787e5dd7070Spatrick     std::error_code EC;
788e5dd7070Spatrick     OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
789a9ac8606Spatrick                                            llvm::sys::fs::OF_TextWithCRLF));
790*12c85518Srobert     OutputStream = OutFile.get();
791e5dd7070Spatrick   }
792*12c85518Srobert   llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
793e5dd7070Spatrick 
794e5dd7070Spatrick   Out << "Information for module file '" << getCurrentFile() << "':\n";
795*12c85518Srobert   auto &FileMgr = CI.getFileManager();
796e5dd7070Spatrick   auto Buffer = FileMgr.getBufferForFile(getCurrentFile());
797e5dd7070Spatrick   StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer();
798e5dd7070Spatrick   bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P' &&
799e5dd7070Spatrick                 Magic[2] == 'C' && Magic[3] == 'H');
800e5dd7070Spatrick   Out << "  Module format: " << (IsRaw ? "raw" : "obj") << "\n";
801e5dd7070Spatrick 
802*12c85518Srobert   Preprocessor &PP = CI.getPreprocessor();
803e5dd7070Spatrick   DumpModuleInfoListener Listener(Out);
804*12c85518Srobert   HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
805*12c85518Srobert 
806*12c85518Srobert   // The FrontendAction::BeginSourceFile () method loads the AST so that much
807*12c85518Srobert   // of the information is already available and modules should have been
808*12c85518Srobert   // loaded.
809*12c85518Srobert 
810*12c85518Srobert   const LangOptions &LO = getCurrentASTUnit().getLangOpts();
811*12c85518Srobert   if (LO.CPlusPlusModules && !LO.CurrentModule.empty()) {
812*12c85518Srobert 
813*12c85518Srobert     ASTReader *R = getCurrentASTUnit().getASTReader().get();
814*12c85518Srobert     unsigned SubModuleCount = R->getTotalNumSubmodules();
815*12c85518Srobert     serialization::ModuleFile &MF = R->getModuleManager().getPrimaryModule();
816*12c85518Srobert     Out << "  ====== C++20 Module structure ======\n";
817*12c85518Srobert 
818*12c85518Srobert     if (MF.ModuleName != LO.CurrentModule)
819*12c85518Srobert       Out << "  Mismatched module names : " << MF.ModuleName << " and "
820*12c85518Srobert           << LO.CurrentModule << "\n";
821*12c85518Srobert 
822*12c85518Srobert     struct SubModInfo {
823*12c85518Srobert       unsigned Idx;
824*12c85518Srobert       Module *Mod;
825*12c85518Srobert       Module::ModuleKind Kind;
826*12c85518Srobert       std::string &Name;
827*12c85518Srobert       bool Seen;
828*12c85518Srobert     };
829*12c85518Srobert     std::map<std::string, SubModInfo> SubModMap;
830*12c85518Srobert     auto PrintSubMapEntry = [&](std::string Name, Module::ModuleKind Kind) {
831*12c85518Srobert       Out << "    " << ModuleKindName(Kind) << " '" << Name << "'";
832*12c85518Srobert       auto I = SubModMap.find(Name);
833*12c85518Srobert       if (I == SubModMap.end())
834*12c85518Srobert         Out << " was not found in the sub modules!\n";
835*12c85518Srobert       else {
836*12c85518Srobert         I->second.Seen = true;
837*12c85518Srobert         Out << " is at index #" << I->second.Idx << "\n";
838*12c85518Srobert       }
839*12c85518Srobert     };
840*12c85518Srobert     Module *Primary = nullptr;
841*12c85518Srobert     for (unsigned Idx = 0; Idx <= SubModuleCount; ++Idx) {
842*12c85518Srobert       Module *M = R->getModule(Idx);
843*12c85518Srobert       if (!M)
844*12c85518Srobert         continue;
845*12c85518Srobert       if (M->Name == LO.CurrentModule) {
846*12c85518Srobert         Primary = M;
847*12c85518Srobert         Out << "  " << ModuleKindName(M->Kind) << " '" << LO.CurrentModule
848*12c85518Srobert             << "' is the Primary Module at index #" << Idx << "\n";
849*12c85518Srobert         SubModMap.insert({M->Name, {Idx, M, M->Kind, M->Name, true}});
850*12c85518Srobert       } else
851*12c85518Srobert         SubModMap.insert({M->Name, {Idx, M, M->Kind, M->Name, false}});
852*12c85518Srobert     }
853*12c85518Srobert     if (Primary) {
854*12c85518Srobert       if (!Primary->submodules().empty())
855*12c85518Srobert         Out << "   Sub Modules:\n";
856*12c85518Srobert       for (auto *MI : Primary->submodules()) {
857*12c85518Srobert         PrintSubMapEntry(MI->Name, MI->Kind);
858*12c85518Srobert       }
859*12c85518Srobert       if (!Primary->Imports.empty())
860*12c85518Srobert         Out << "   Imports:\n";
861*12c85518Srobert       for (auto *IMP : Primary->Imports) {
862*12c85518Srobert         PrintSubMapEntry(IMP->Name, IMP->Kind);
863*12c85518Srobert       }
864*12c85518Srobert       if (!Primary->Exports.empty())
865*12c85518Srobert         Out << "   Exports:\n";
866*12c85518Srobert       for (unsigned MN = 0, N = Primary->Exports.size(); MN != N; ++MN) {
867*12c85518Srobert         if (Module *M = Primary->Exports[MN].getPointer()) {
868*12c85518Srobert           PrintSubMapEntry(M->Name, M->Kind);
869*12c85518Srobert         }
870*12c85518Srobert       }
871*12c85518Srobert     }
872*12c85518Srobert 
873*12c85518Srobert     // Emit the macro definitions in the module file so that we can know how
874*12c85518Srobert     // much definitions in the module file quickly.
875*12c85518Srobert     // TODO: Emit the macro definition bodies completely.
876*12c85518Srobert     if (auto FilteredMacros = llvm::make_filter_range(
877*12c85518Srobert             R->getPreprocessor().macros(),
878*12c85518Srobert             [](const auto &Macro) { return Macro.first->isFromAST(); });
879*12c85518Srobert         !FilteredMacros.empty()) {
880*12c85518Srobert       Out << "   Macro Definitions:\n";
881*12c85518Srobert       for (/*<IdentifierInfo *, MacroState> pair*/ const auto &Macro :
882*12c85518Srobert            FilteredMacros)
883*12c85518Srobert         Out << "     " << Macro.first->getName() << "\n";
884*12c85518Srobert     }
885*12c85518Srobert 
886*12c85518Srobert     // Now let's print out any modules we did not see as part of the Primary.
887*12c85518Srobert     for (auto SM : SubModMap) {
888*12c85518Srobert       if (!SM.second.Seen && SM.second.Mod) {
889*12c85518Srobert         Out << "  " << ModuleKindName(SM.second.Kind) << " '" << SM.first
890*12c85518Srobert             << "' at index #" << SM.second.Idx
891*12c85518Srobert             << " has no direct reference in the Primary\n";
892*12c85518Srobert       }
893*12c85518Srobert     }
894*12c85518Srobert     Out << "  ====== ======\n";
895*12c85518Srobert   }
896*12c85518Srobert 
897*12c85518Srobert   // The reminder of the output is produced from the listener as the AST
898*12c85518Srobert   // FileCcontrolBlock is (re-)parsed.
899e5dd7070Spatrick   ASTReader::readASTFileControlBlock(
900*12c85518Srobert       getCurrentFile(), FileMgr, CI.getModuleCache(),
901*12c85518Srobert       CI.getPCHContainerReader(),
902e5dd7070Spatrick       /*FindModuleFileExtensions=*/true, Listener,
903e5dd7070Spatrick       HSOpts.ModulesValidateDiagnosticOptions);
904e5dd7070Spatrick }
905e5dd7070Spatrick 
906e5dd7070Spatrick //===----------------------------------------------------------------------===//
907e5dd7070Spatrick // Preprocessor Actions
908e5dd7070Spatrick //===----------------------------------------------------------------------===//
909e5dd7070Spatrick 
ExecuteAction()910e5dd7070Spatrick void DumpRawTokensAction::ExecuteAction() {
911e5dd7070Spatrick   Preprocessor &PP = getCompilerInstance().getPreprocessor();
912e5dd7070Spatrick   SourceManager &SM = PP.getSourceManager();
913e5dd7070Spatrick 
914e5dd7070Spatrick   // Start lexing the specified input file.
915a9ac8606Spatrick   llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID());
916e5dd7070Spatrick   Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
917e5dd7070Spatrick   RawLex.SetKeepWhitespaceMode(true);
918e5dd7070Spatrick 
919e5dd7070Spatrick   Token RawTok;
920e5dd7070Spatrick   RawLex.LexFromRawLexer(RawTok);
921e5dd7070Spatrick   while (RawTok.isNot(tok::eof)) {
922e5dd7070Spatrick     PP.DumpToken(RawTok, true);
923e5dd7070Spatrick     llvm::errs() << "\n";
924e5dd7070Spatrick     RawLex.LexFromRawLexer(RawTok);
925e5dd7070Spatrick   }
926e5dd7070Spatrick }
927e5dd7070Spatrick 
ExecuteAction()928e5dd7070Spatrick void DumpTokensAction::ExecuteAction() {
929e5dd7070Spatrick   Preprocessor &PP = getCompilerInstance().getPreprocessor();
930e5dd7070Spatrick   // Start preprocessing the specified input file.
931e5dd7070Spatrick   Token Tok;
932e5dd7070Spatrick   PP.EnterMainSourceFile();
933e5dd7070Spatrick   do {
934e5dd7070Spatrick     PP.Lex(Tok);
935e5dd7070Spatrick     PP.DumpToken(Tok, true);
936e5dd7070Spatrick     llvm::errs() << "\n";
937e5dd7070Spatrick   } while (Tok.isNot(tok::eof));
938e5dd7070Spatrick }
939e5dd7070Spatrick 
ExecuteAction()940e5dd7070Spatrick void PreprocessOnlyAction::ExecuteAction() {
941e5dd7070Spatrick   Preprocessor &PP = getCompilerInstance().getPreprocessor();
942e5dd7070Spatrick 
943e5dd7070Spatrick   // Ignore unknown pragmas.
944e5dd7070Spatrick   PP.IgnorePragmas();
945e5dd7070Spatrick 
946e5dd7070Spatrick   Token Tok;
947e5dd7070Spatrick   // Start parsing the specified input file.
948e5dd7070Spatrick   PP.EnterMainSourceFile();
949e5dd7070Spatrick   do {
950e5dd7070Spatrick     PP.Lex(Tok);
951e5dd7070Spatrick   } while (Tok.isNot(tok::eof));
952e5dd7070Spatrick }
953e5dd7070Spatrick 
ExecuteAction()954e5dd7070Spatrick void PrintPreprocessedAction::ExecuteAction() {
955e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
956e5dd7070Spatrick   // Output file may need to be set to 'Binary', to avoid converting Unix style
957a9ac8606Spatrick   // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>) on Windows.
958e5dd7070Spatrick   //
959e5dd7070Spatrick   // Look to see what type of line endings the file uses. If there's a
960e5dd7070Spatrick   // CRLF, then we won't open the file up in binary mode. If there is
961e5dd7070Spatrick   // just an LF or CR, then we will open the file up in binary mode.
962e5dd7070Spatrick   // In this fashion, the output format should match the input format, unless
963e5dd7070Spatrick   // the input format has inconsistent line endings.
964e5dd7070Spatrick   //
965e5dd7070Spatrick   // This should be a relatively fast operation since most files won't have
966e5dd7070Spatrick   // all of their source code on a single line. However, that is still a
967e5dd7070Spatrick   // concern, so if we scan for too long, we'll just assume the file should
968e5dd7070Spatrick   // be opened in binary mode.
969a9ac8606Spatrick 
970a9ac8606Spatrick   bool BinaryMode = false;
971a9ac8606Spatrick   if (llvm::Triple(LLVM_HOST_TRIPLE).isOSWindows()) {
972a9ac8606Spatrick     BinaryMode = true;
973e5dd7070Spatrick     const SourceManager &SM = CI.getSourceManager();
974*12c85518Srobert     if (std::optional<llvm::MemoryBufferRef> Buffer =
975a9ac8606Spatrick             SM.getBufferOrNone(SM.getMainFileID())) {
976e5dd7070Spatrick       const char *cur = Buffer->getBufferStart();
977e5dd7070Spatrick       const char *end = Buffer->getBufferEnd();
978e5dd7070Spatrick       const char *next = (cur != end) ? cur + 1 : end;
979e5dd7070Spatrick 
980e5dd7070Spatrick       // Limit ourselves to only scanning 256 characters into the source
981*12c85518Srobert       // file.  This is mostly a check in case the file has no
982e5dd7070Spatrick       // newlines whatsoever.
983a9ac8606Spatrick       if (end - cur > 256)
984a9ac8606Spatrick         end = cur + 256;
985e5dd7070Spatrick 
986e5dd7070Spatrick       while (next < end) {
987e5dd7070Spatrick         if (*cur == 0x0D) {  // CR
988e5dd7070Spatrick           if (*next == 0x0A) // CRLF
989e5dd7070Spatrick             BinaryMode = false;
990e5dd7070Spatrick 
991e5dd7070Spatrick           break;
992e5dd7070Spatrick         } else if (*cur == 0x0A) // LF
993e5dd7070Spatrick           break;
994e5dd7070Spatrick 
995e5dd7070Spatrick         ++cur;
996e5dd7070Spatrick         ++next;
997e5dd7070Spatrick       }
998e5dd7070Spatrick     }
999a9ac8606Spatrick   }
1000e5dd7070Spatrick 
1001e5dd7070Spatrick   std::unique_ptr<raw_ostream> OS =
1002e5dd7070Spatrick       CI.createDefaultOutputFile(BinaryMode, getCurrentFileOrBufferName());
1003e5dd7070Spatrick   if (!OS) return;
1004e5dd7070Spatrick 
1005e5dd7070Spatrick   // If we're preprocessing a module map, start by dumping the contents of the
1006e5dd7070Spatrick   // module itself before switching to the input buffer.
1007e5dd7070Spatrick   auto &Input = getCurrentInput();
1008e5dd7070Spatrick   if (Input.getKind().getFormat() == InputKind::ModuleMap) {
1009e5dd7070Spatrick     if (Input.isFile()) {
1010e5dd7070Spatrick       (*OS) << "# 1 \"";
1011e5dd7070Spatrick       OS->write_escaped(Input.getFile());
1012e5dd7070Spatrick       (*OS) << "\"\n";
1013e5dd7070Spatrick     }
1014e5dd7070Spatrick     getCurrentModule()->print(*OS);
1015e5dd7070Spatrick     (*OS) << "#pragma clang module contents\n";
1016e5dd7070Spatrick   }
1017e5dd7070Spatrick 
1018e5dd7070Spatrick   DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(),
1019e5dd7070Spatrick                            CI.getPreprocessorOutputOpts());
1020e5dd7070Spatrick }
1021e5dd7070Spatrick 
ExecuteAction()1022e5dd7070Spatrick void PrintPreambleAction::ExecuteAction() {
1023e5dd7070Spatrick   switch (getCurrentFileKind().getLanguage()) {
1024e5dd7070Spatrick   case Language::C:
1025e5dd7070Spatrick   case Language::CXX:
1026e5dd7070Spatrick   case Language::ObjC:
1027e5dd7070Spatrick   case Language::ObjCXX:
1028e5dd7070Spatrick   case Language::OpenCL:
1029a9ac8606Spatrick   case Language::OpenCLCXX:
1030e5dd7070Spatrick   case Language::CUDA:
1031e5dd7070Spatrick   case Language::HIP:
1032*12c85518Srobert   case Language::HLSL:
1033e5dd7070Spatrick     break;
1034e5dd7070Spatrick 
1035e5dd7070Spatrick   case Language::Unknown:
1036e5dd7070Spatrick   case Language::Asm:
1037e5dd7070Spatrick   case Language::LLVM_IR:
1038e5dd7070Spatrick   case Language::RenderScript:
1039e5dd7070Spatrick     // We can't do anything with these.
1040e5dd7070Spatrick     return;
1041e5dd7070Spatrick   }
1042e5dd7070Spatrick 
1043e5dd7070Spatrick   // We don't expect to find any #include directives in a preprocessed input.
1044e5dd7070Spatrick   if (getCurrentFileKind().isPreprocessed())
1045e5dd7070Spatrick     return;
1046e5dd7070Spatrick 
1047e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
1048e5dd7070Spatrick   auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
1049e5dd7070Spatrick   if (Buffer) {
1050e5dd7070Spatrick     unsigned Preamble =
1051e5dd7070Spatrick         Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).Size;
1052e5dd7070Spatrick     llvm::outs().write((*Buffer)->getBufferStart(), Preamble);
1053e5dd7070Spatrick   }
1054e5dd7070Spatrick }
1055e5dd7070Spatrick 
ExecuteAction()1056e5dd7070Spatrick void DumpCompilerOptionsAction::ExecuteAction() {
1057e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
1058e5dd7070Spatrick   std::unique_ptr<raw_ostream> OSP =
1059e5dd7070Spatrick       CI.createDefaultOutputFile(false, getCurrentFile());
1060e5dd7070Spatrick   if (!OSP)
1061e5dd7070Spatrick     return;
1062e5dd7070Spatrick 
1063e5dd7070Spatrick   raw_ostream &OS = *OSP;
1064e5dd7070Spatrick   const Preprocessor &PP = CI.getPreprocessor();
1065e5dd7070Spatrick   const LangOptions &LangOpts = PP.getLangOpts();
1066e5dd7070Spatrick 
1067e5dd7070Spatrick   // FIXME: Rather than manually format the JSON (which is awkward due to
1068e5dd7070Spatrick   // needing to remove trailing commas), this should make use of a JSON library.
1069e5dd7070Spatrick   // FIXME: Instead of printing enums as an integral value and specifying the
1070e5dd7070Spatrick   // type as a separate field, use introspection to print the enumerator.
1071e5dd7070Spatrick 
1072e5dd7070Spatrick   OS << "{\n";
1073e5dd7070Spatrick   OS << "\n\"features\" : [\n";
1074e5dd7070Spatrick   {
1075e5dd7070Spatrick     llvm::SmallString<128> Str;
1076e5dd7070Spatrick #define FEATURE(Name, Predicate)                                               \
1077e5dd7070Spatrick   ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \
1078e5dd7070Spatrick       .toVector(Str);
1079e5dd7070Spatrick #include "clang/Basic/Features.def"
1080e5dd7070Spatrick #undef FEATURE
1081e5dd7070Spatrick     // Remove the newline and comma from the last entry to ensure this remains
1082e5dd7070Spatrick     // valid JSON.
1083e5dd7070Spatrick     OS << Str.substr(0, Str.size() - 2);
1084e5dd7070Spatrick   }
1085e5dd7070Spatrick   OS << "\n],\n";
1086e5dd7070Spatrick 
1087e5dd7070Spatrick   OS << "\n\"extensions\" : [\n";
1088e5dd7070Spatrick   {
1089e5dd7070Spatrick     llvm::SmallString<128> Str;
1090e5dd7070Spatrick #define EXTENSION(Name, Predicate)                                             \
1091e5dd7070Spatrick   ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \
1092e5dd7070Spatrick       .toVector(Str);
1093e5dd7070Spatrick #include "clang/Basic/Features.def"
1094e5dd7070Spatrick #undef EXTENSION
1095e5dd7070Spatrick     // Remove the newline and comma from the last entry to ensure this remains
1096e5dd7070Spatrick     // valid JSON.
1097e5dd7070Spatrick     OS << Str.substr(0, Str.size() - 2);
1098e5dd7070Spatrick   }
1099e5dd7070Spatrick   OS << "\n]\n";
1100e5dd7070Spatrick 
1101e5dd7070Spatrick   OS << "}";
1102e5dd7070Spatrick }
1103e5dd7070Spatrick 
ExecuteAction()1104e5dd7070Spatrick void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
1105e5dd7070Spatrick   CompilerInstance &CI = getCompilerInstance();
1106e5dd7070Spatrick   SourceManager &SM = CI.getPreprocessor().getSourceManager();
1107a9ac8606Spatrick   llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID());
1108e5dd7070Spatrick 
1109*12c85518Srobert   llvm::SmallVector<dependency_directives_scan::Token, 16> Tokens;
1110*12c85518Srobert   llvm::SmallVector<dependency_directives_scan::Directive, 32> Directives;
1111*12c85518Srobert   if (scanSourceForDependencyDirectives(
1112*12c85518Srobert           FromFile.getBuffer(), Tokens, Directives, &CI.getDiagnostics(),
1113e5dd7070Spatrick           SM.getLocForStartOfFile(SM.getMainFileID()))) {
1114e5dd7070Spatrick     assert(CI.getDiagnostics().hasErrorOccurred() &&
1115e5dd7070Spatrick            "no errors reported for failure");
1116e5dd7070Spatrick 
1117e5dd7070Spatrick     // Preprocess the source when verifying the diagnostics to capture the
1118e5dd7070Spatrick     // 'expected' comments.
1119e5dd7070Spatrick     if (CI.getDiagnosticOpts().VerifyDiagnostics) {
1120e5dd7070Spatrick       // Make sure we don't emit new diagnostics!
1121e5dd7070Spatrick       CI.getDiagnostics().setSuppressAllDiagnostics(true);
1122e5dd7070Spatrick       Preprocessor &PP = getCompilerInstance().getPreprocessor();
1123e5dd7070Spatrick       PP.EnterMainSourceFile();
1124e5dd7070Spatrick       Token Tok;
1125e5dd7070Spatrick       do {
1126e5dd7070Spatrick         PP.Lex(Tok);
1127e5dd7070Spatrick       } while (Tok.isNot(tok::eof));
1128e5dd7070Spatrick     }
1129e5dd7070Spatrick     return;
1130e5dd7070Spatrick   }
1131*12c85518Srobert   printDependencyDirectivesAsSource(FromFile.getBuffer(), Directives,
1132*12c85518Srobert                                     llvm::outs());
1133*12c85518Srobert }
1134*12c85518Srobert 
ExecuteAction()1135*12c85518Srobert void GetDependenciesByModuleNameAction::ExecuteAction() {
1136*12c85518Srobert   CompilerInstance &CI = getCompilerInstance();
1137*12c85518Srobert   Preprocessor &PP = CI.getPreprocessor();
1138*12c85518Srobert   SourceManager &SM = PP.getSourceManager();
1139*12c85518Srobert   FileID MainFileID = SM.getMainFileID();
1140*12c85518Srobert   SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
1141*12c85518Srobert   SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
1142*12c85518Srobert   IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
1143*12c85518Srobert   Path.push_back(std::make_pair(ModuleID, FileStart));
1144*12c85518Srobert   auto ModResult = CI.loadModule(FileStart, Path, Module::Hidden, false);
1145*12c85518Srobert   PPCallbacks *CB = PP.getPPCallbacks();
1146*12c85518Srobert   CB->moduleImport(SourceLocation(), Path, ModResult);
1147e5dd7070Spatrick }
1148