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