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