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