/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Frontend/FrontendActions.cpp
Line | Count | Source (jump to first uncovered line) |
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/Basic/FileManager.h" |
12 | | #include "clang/Basic/TargetInfo.h" |
13 | | #include "clang/Basic/LangStandard.h" |
14 | | #include "clang/Frontend/ASTConsumers.h" |
15 | | #include "clang/Frontend/CompilerInstance.h" |
16 | | #include "clang/Frontend/FrontendDiagnostic.h" |
17 | | #include "clang/Frontend/MultiplexConsumer.h" |
18 | | #include "clang/Frontend/Utils.h" |
19 | | #include "clang/Lex/DependencyDirectivesSourceMinimizer.h" |
20 | | #include "clang/Lex/HeaderSearch.h" |
21 | | #include "clang/Lex/Preprocessor.h" |
22 | | #include "clang/Lex/PreprocessorOptions.h" |
23 | | #include "clang/Sema/TemplateInstCallback.h" |
24 | | #include "clang/Serialization/ASTReader.h" |
25 | | #include "clang/Serialization/ASTWriter.h" |
26 | | #include "llvm/Support/FileSystem.h" |
27 | | #include "llvm/Support/MemoryBuffer.h" |
28 | | #include "llvm/Support/Path.h" |
29 | | #include "llvm/Support/YAMLTraits.h" |
30 | | #include "llvm/Support/raw_ostream.h" |
31 | | #include <memory> |
32 | | #include <system_error> |
33 | | |
34 | | using namespace clang; |
35 | | |
36 | | namespace { |
37 | 11 | CodeCompleteConsumer *GetCodeCompletionConsumer(CompilerInstance &CI) { |
38 | 0 | return CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() |
39 | 11 | : nullptr; |
40 | 11 | } |
41 | | |
42 | 11 | void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) { |
43 | 11 | if (Action.hasCodeCompletionSupport() && |
44 | 0 | !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) |
45 | 0 | CI.createCodeCompletionConsumer(); |
46 | | |
47 | 11 | if (!CI.hasSema()) |
48 | 11 | CI.createSema(Action.getTranslationUnitKind(), |
49 | 11 | GetCodeCompletionConsumer(CI)); |
50 | 11 | } |
51 | | } // namespace |
52 | | |
53 | | //===----------------------------------------------------------------------===// |
54 | | // Custom Actions |
55 | | //===----------------------------------------------------------------------===// |
56 | | |
57 | | std::unique_ptr<ASTConsumer> |
58 | 0 | InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
59 | 0 | return std::make_unique<ASTConsumer>(); |
60 | 0 | } |
61 | | |
62 | 0 | void InitOnlyAction::ExecuteAction() { |
63 | 0 | } |
64 | | |
65 | | //===----------------------------------------------------------------------===// |
66 | | // AST Consumer Actions |
67 | | //===----------------------------------------------------------------------===// |
68 | | |
69 | | std::unique_ptr<ASTConsumer> |
70 | 532 | ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
71 | 532 | if (std::unique_ptr<raw_ostream> OS = |
72 | 532 | CI.createDefaultOutputFile(false, InFile)) |
73 | 532 | return CreateASTPrinter(std::move(OS), CI.getFrontendOpts().ASTDumpFilter); |
74 | 0 | return nullptr; |
75 | 0 | } |
76 | | |
77 | | std::unique_ptr<ASTConsumer> |
78 | 410 | ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
79 | 410 | const FrontendOptions &Opts = CI.getFrontendOpts(); |
80 | 410 | return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter, |
81 | 410 | Opts.ASTDumpDecls, Opts.ASTDumpAll, |
82 | 410 | Opts.ASTDumpLookups, Opts.ASTDumpDeclTypes, |
83 | 410 | Opts.ASTDumpFormat); |
84 | 410 | } |
85 | | |
86 | | std::unique_ptr<ASTConsumer> |
87 | 0 | ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
88 | 0 | return CreateASTDeclNodeLister(); |
89 | 0 | } |
90 | | |
91 | | std::unique_ptr<ASTConsumer> |
92 | 0 | ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
93 | 0 | return CreateASTViewer(); |
94 | 0 | } |
95 | | |
96 | | std::unique_ptr<ASTConsumer> |
97 | 3.10k | GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
98 | 3.10k | std::string Sysroot; |
99 | 3.10k | if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot)) |
100 | 0 | return nullptr; |
101 | | |
102 | 3.10k | std::string OutputFile; |
103 | 3.10k | std::unique_ptr<raw_pwrite_stream> OS = |
104 | 3.10k | CreateOutputFile(CI, InFile, /*ref*/ OutputFile); |
105 | 3.10k | if (!OS) |
106 | 0 | return nullptr; |
107 | | |
108 | 3.10k | if (!CI.getFrontendOpts().RelocatablePCH) |
109 | 3.10k | Sysroot.clear(); |
110 | | |
111 | 3.10k | const auto &FrontendOpts = CI.getFrontendOpts(); |
112 | 3.10k | auto Buffer = std::make_shared<PCHBuffer>(); |
113 | 3.10k | std::vector<std::unique_ptr<ASTConsumer>> Consumers; |
114 | 3.10k | Consumers.push_back(std::make_unique<PCHGenerator>( |
115 | 3.10k | CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer, |
116 | 3.10k | FrontendOpts.ModuleFileExtensions, |
117 | 3.10k | CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, |
118 | 3.10k | FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH)); |
119 | 3.10k | Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator( |
120 | 3.10k | CI, std::string(InFile), OutputFile, std::move(OS), Buffer)); |
121 | | |
122 | 3.10k | return std::make_unique<MultiplexConsumer>(std::move(Consumers)); |
123 | 3.10k | } |
124 | | |
125 | | bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, |
126 | 3.19k | std::string &Sysroot) { |
127 | 3.19k | Sysroot = CI.getHeaderSearchOpts().Sysroot; |
128 | 3.19k | if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()1 ) { |
129 | 0 | CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | 3.19k | return true; |
134 | 3.19k | } |
135 | | |
136 | | std::unique_ptr<llvm::raw_pwrite_stream> |
137 | | GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile, |
138 | 3.19k | std::string &OutputFile) { |
139 | | // We use createOutputFile here because this is exposed via libclang, and we |
140 | | // must disable the RemoveFileOnSignal behavior. |
141 | | // We use a temporary to avoid race conditions. |
142 | 3.19k | std::unique_ptr<raw_pwrite_stream> OS = |
143 | 3.19k | CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, |
144 | 3.19k | /*RemoveFileOnSignal=*/false, InFile, |
145 | 3.19k | /*Extension=*/"", CI.getFrontendOpts().UseTemporary); |
146 | 3.19k | if (!OS) |
147 | 0 | return nullptr; |
148 | | |
149 | 3.19k | OutputFile = CI.getFrontendOpts().OutputFile; |
150 | 3.19k | return OS; |
151 | 3.19k | } |
152 | | |
153 | 3.10k | bool GeneratePCHAction::shouldEraseOutputFiles() { |
154 | 3.10k | if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors) |
155 | 7 | return false; |
156 | 3.10k | return ASTFrontendAction::shouldEraseOutputFiles(); |
157 | 3.10k | } |
158 | | |
159 | 3.10k | bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) { |
160 | 3.10k | CI.getLangOpts().CompilingPCH = true; |
161 | 3.10k | return true; |
162 | 3.10k | } |
163 | | |
164 | | std::unique_ptr<ASTConsumer> |
165 | | GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, |
166 | 1.88k | StringRef InFile) { |
167 | 1.88k | std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile); |
168 | 1.88k | if (!OS) |
169 | 0 | return nullptr; |
170 | | |
171 | 1.88k | std::string OutputFile = CI.getFrontendOpts().OutputFile; |
172 | 1.88k | std::string Sysroot; |
173 | | |
174 | 1.88k | auto Buffer = std::make_shared<PCHBuffer>(); |
175 | 1.88k | std::vector<std::unique_ptr<ASTConsumer>> Consumers; |
176 | | |
177 | 1.88k | Consumers.push_back(std::make_unique<PCHGenerator>( |
178 | 1.88k | CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer, |
179 | 1.88k | CI.getFrontendOpts().ModuleFileExtensions, |
180 | | /*AllowASTWithErrors=*/ |
181 | 1.88k | +CI.getFrontendOpts().AllowPCMWithCompilerErrors, |
182 | | /*IncludeTimestamps=*/ |
183 | 1.88k | +CI.getFrontendOpts().BuildingImplicitModule, |
184 | | /*ShouldCacheASTInMemory=*/ |
185 | 1.88k | +CI.getFrontendOpts().BuildingImplicitModule)); |
186 | 1.88k | Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator( |
187 | 1.88k | CI, std::string(InFile), OutputFile, std::move(OS), Buffer)); |
188 | 1.88k | return std::make_unique<MultiplexConsumer>(std::move(Consumers)); |
189 | 1.88k | } |
190 | | |
191 | 1.88k | bool GenerateModuleAction::shouldEraseOutputFiles() { |
192 | 1.88k | return !getCompilerInstance().getFrontendOpts().AllowPCMWithCompilerErrors && |
193 | 1.88k | ASTFrontendAction::shouldEraseOutputFiles(); |
194 | 1.88k | } |
195 | | |
196 | | bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( |
197 | 1.83k | CompilerInstance &CI) { |
198 | 1.83k | if (!CI.getLangOpts().Modules) { |
199 | 1 | CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules); |
200 | 1 | return false; |
201 | 1 | } |
202 | | |
203 | 1.83k | return GenerateModuleAction::BeginSourceFileAction(CI); |
204 | 1.83k | } |
205 | | |
206 | | std::unique_ptr<raw_pwrite_stream> |
207 | | GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, |
208 | 1.83k | StringRef InFile) { |
209 | | // If no output file was provided, figure out where this module would go |
210 | | // in the module cache. |
211 | 1.83k | if (CI.getFrontendOpts().OutputFile.empty()) { |
212 | 48 | StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap; |
213 | 48 | if (ModuleMapFile.empty()) |
214 | 48 | ModuleMapFile = InFile; |
215 | | |
216 | 48 | HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); |
217 | 48 | CI.getFrontendOpts().OutputFile = |
218 | 48 | HS.getCachedModuleFileName(CI.getLangOpts().CurrentModule, |
219 | 48 | ModuleMapFile); |
220 | 48 | } |
221 | | |
222 | | // We use createOutputFile here because this is exposed via libclang, and we |
223 | | // must disable the RemoveFileOnSignal behavior. |
224 | | // We use a temporary to avoid race conditions. |
225 | 1.83k | return CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, |
226 | 1.83k | /*RemoveFileOnSignal=*/false, InFile, |
227 | 1.83k | /*Extension=*/"", /*UseTemporary=*/true, |
228 | 1.83k | /*CreateMissingDirectories=*/true); |
229 | 1.83k | } |
230 | | |
231 | | bool GenerateModuleInterfaceAction::BeginSourceFileAction( |
232 | 49 | CompilerInstance &CI) { |
233 | 49 | if (!CI.getLangOpts().ModulesTS && !CI.getLangOpts().CPlusPlusModules10 ) { |
234 | 0 | CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules); |
235 | 0 | return false; |
236 | 0 | } |
237 | | |
238 | 49 | CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); |
239 | | |
240 | 49 | return GenerateModuleAction::BeginSourceFileAction(CI); |
241 | 49 | } |
242 | | |
243 | | std::unique_ptr<raw_pwrite_stream> |
244 | | GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI, |
245 | 49 | StringRef InFile) { |
246 | 49 | return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm"); |
247 | 49 | } |
248 | | |
249 | | bool GenerateHeaderModuleAction::PrepareToExecuteAction( |
250 | 6 | CompilerInstance &CI) { |
251 | 6 | if (!CI.getLangOpts().Modules) { |
252 | 0 | CI.getDiagnostics().Report(diag::err_header_module_requires_modules); |
253 | 0 | return false; |
254 | 0 | } |
255 | | |
256 | 6 | auto &Inputs = CI.getFrontendOpts().Inputs; |
257 | 6 | if (Inputs.empty()) |
258 | 0 | return GenerateModuleAction::BeginInvocation(CI); |
259 | | |
260 | 6 | auto Kind = Inputs[0].getKind(); |
261 | | |
262 | | // Convert the header file inputs into a single module input buffer. |
263 | 6 | SmallString<256> HeaderContents; |
264 | 6 | ModuleHeaders.reserve(Inputs.size()); |
265 | 11 | for (const FrontendInputFile &FIF : Inputs) { |
266 | | // FIXME: We should support re-compiling from an AST file. |
267 | 11 | if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) { |
268 | 0 | CI.getDiagnostics().Report(diag::err_module_header_file_not_found) |
269 | 0 | << (FIF.isFile() ? FIF.getFile() |
270 | 0 | : FIF.getBuffer().getBufferIdentifier()); |
271 | 0 | return true; |
272 | 0 | } |
273 | | |
274 | 11 | HeaderContents += "#include \""; |
275 | 11 | HeaderContents += FIF.getFile(); |
276 | 11 | HeaderContents += "\"\n"; |
277 | 11 | ModuleHeaders.push_back(std::string(FIF.getFile())); |
278 | 11 | } |
279 | 6 | Buffer = llvm::MemoryBuffer::getMemBufferCopy( |
280 | 6 | HeaderContents, Module::getModuleInputBufferName()); |
281 | | |
282 | | // Set that buffer up as our "real" input. |
283 | 6 | Inputs.clear(); |
284 | 6 | Inputs.push_back( |
285 | 6 | FrontendInputFile(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false)); |
286 | | |
287 | 6 | return GenerateModuleAction::PrepareToExecuteAction(CI); |
288 | 6 | } |
289 | | |
290 | | bool GenerateHeaderModuleAction::BeginSourceFileAction( |
291 | 6 | CompilerInstance &CI) { |
292 | 6 | CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule); |
293 | | |
294 | | // Synthesize a Module object for the given headers. |
295 | 6 | auto &HS = CI.getPreprocessor().getHeaderSearchInfo(); |
296 | 6 | SmallVector<Module::Header, 16> Headers; |
297 | 11 | for (StringRef Name : ModuleHeaders) { |
298 | 11 | const DirectoryLookup *CurDir = nullptr; |
299 | 11 | Optional<FileEntryRef> FE = HS.LookupFile( |
300 | 11 | Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None, |
301 | 11 | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); |
302 | 11 | if (!FE) { |
303 | 0 | CI.getDiagnostics().Report(diag::err_module_header_file_not_found) |
304 | 0 | << Name; |
305 | 0 | continue; |
306 | 0 | } |
307 | 11 | Headers.push_back({std::string(Name), *FE}); |
308 | 11 | } |
309 | 6 | HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers); |
310 | | |
311 | 6 | return GenerateModuleAction::BeginSourceFileAction(CI); |
312 | 6 | } |
313 | | |
314 | | std::unique_ptr<raw_pwrite_stream> |
315 | | GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI, |
316 | 6 | StringRef InFile) { |
317 | 6 | return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm"); |
318 | 6 | } |
319 | | |
320 | 13.0k | SyntaxOnlyAction::~SyntaxOnlyAction() { |
321 | 13.0k | } |
322 | | |
323 | | std::unique_ptr<ASTConsumer> |
324 | 13.2k | SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
325 | 13.2k | return std::make_unique<ASTConsumer>(); |
326 | 13.2k | } |
327 | | |
328 | | std::unique_ptr<ASTConsumer> |
329 | | DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI, |
330 | 5 | StringRef InFile) { |
331 | 5 | return std::make_unique<ASTConsumer>(); |
332 | 5 | } |
333 | | |
334 | | std::unique_ptr<ASTConsumer> |
335 | 7 | VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
336 | 7 | return std::make_unique<ASTConsumer>(); |
337 | 7 | } |
338 | | |
339 | 7 | void VerifyPCHAction::ExecuteAction() { |
340 | 7 | CompilerInstance &CI = getCompilerInstance(); |
341 | 7 | bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; |
342 | 7 | const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; |
343 | 7 | std::unique_ptr<ASTReader> Reader(new ASTReader( |
344 | 7 | CI.getPreprocessor(), CI.getModuleCache(), &CI.getASTContext(), |
345 | 7 | CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions, |
346 | 7 | Sysroot.empty() ? ""0 : Sysroot.c_str(), |
347 | 7 | DisableValidationForModuleKind::None, |
348 | 7 | /*AllowASTWithCompilerErrors*/ false, |
349 | 7 | /*AllowConfigurationMismatch*/ true, |
350 | 7 | /*ValidateSystemInputs*/ true)); |
351 | | |
352 | 7 | Reader->ReadAST(getCurrentFile(), |
353 | 0 | Preamble ? serialization::MK_Preamble |
354 | 7 | : serialization::MK_PCH, |
355 | 7 | SourceLocation(), |
356 | 7 | ASTReader::ARR_ConfigurationMismatch); |
357 | 7 | } |
358 | | |
359 | | namespace { |
360 | | struct TemplightEntry { |
361 | | std::string Name; |
362 | | std::string Kind; |
363 | | std::string Event; |
364 | | std::string DefinitionLocation; |
365 | | std::string PointOfInstantiation; |
366 | | }; |
367 | | } // namespace |
368 | | |
369 | | namespace llvm { |
370 | | namespace yaml { |
371 | | template <> struct MappingTraits<TemplightEntry> { |
372 | 152 | static void mapping(IO &io, TemplightEntry &fields) { |
373 | 152 | io.mapRequired("name", fields.Name); |
374 | 152 | io.mapRequired("kind", fields.Kind); |
375 | 152 | io.mapRequired("event", fields.Event); |
376 | 152 | io.mapRequired("orig", fields.DefinitionLocation); |
377 | 152 | io.mapRequired("poi", fields.PointOfInstantiation); |
378 | 152 | } |
379 | | }; |
380 | | } // namespace yaml |
381 | | } // namespace llvm |
382 | | |
383 | | namespace { |
384 | | class DefaultTemplateInstCallback : public TemplateInstantiationCallback { |
385 | | using CodeSynthesisContext = Sema::CodeSynthesisContext; |
386 | | |
387 | | public: |
388 | 11 | void initialize(const Sema &) override {} |
389 | | |
390 | 11 | void finalize(const Sema &) override {} |
391 | | |
392 | | void atTemplateBegin(const Sema &TheSema, |
393 | 76 | const CodeSynthesisContext &Inst) override { |
394 | 76 | displayTemplightEntry<true>(llvm::outs(), TheSema, Inst); |
395 | 76 | } |
396 | | |
397 | | void atTemplateEnd(const Sema &TheSema, |
398 | 76 | const CodeSynthesisContext &Inst) override { |
399 | 76 | displayTemplightEntry<false>(llvm::outs(), TheSema, Inst); |
400 | 76 | } |
401 | | |
402 | | private: |
403 | 152 | static std::string toString(CodeSynthesisContext::SynthesisKind Kind) { |
404 | 152 | switch (Kind) { |
405 | 56 | case CodeSynthesisContext::TemplateInstantiation: |
406 | 56 | return "TemplateInstantiation"; |
407 | 2 | case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: |
408 | 2 | return "DefaultTemplateArgumentInstantiation"; |
409 | 2 | case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: |
410 | 2 | return "DefaultFunctionArgumentInstantiation"; |
411 | 6 | case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: |
412 | 6 | return "ExplicitTemplateArgumentSubstitution"; |
413 | 8 | case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: |
414 | 8 | return "DeducedTemplateArgumentSubstitution"; |
415 | 2 | case CodeSynthesisContext::PriorTemplateArgumentSubstitution: |
416 | 2 | return "PriorTemplateArgumentSubstitution"; |
417 | 4 | case CodeSynthesisContext::DefaultTemplateArgumentChecking: |
418 | 4 | return "DefaultTemplateArgumentChecking"; |
419 | 0 | case CodeSynthesisContext::ExceptionSpecEvaluation: |
420 | 0 | return "ExceptionSpecEvaluation"; |
421 | 2 | case CodeSynthesisContext::ExceptionSpecInstantiation: |
422 | 2 | return "ExceptionSpecInstantiation"; |
423 | 0 | case CodeSynthesisContext::DeclaringSpecialMember: |
424 | 0 | return "DeclaringSpecialMember"; |
425 | 0 | case CodeSynthesisContext::DeclaringImplicitEqualityComparison: |
426 | 0 | return "DeclaringImplicitEqualityComparison"; |
427 | 0 | case CodeSynthesisContext::DefiningSynthesizedFunction: |
428 | 0 | return "DefiningSynthesizedFunction"; |
429 | 0 | case CodeSynthesisContext::RewritingOperatorAsSpaceship: |
430 | 0 | return "RewritingOperatorAsSpaceship"; |
431 | 70 | case CodeSynthesisContext::Memoization: |
432 | 70 | return "Memoization"; |
433 | 0 | case CodeSynthesisContext::ConstraintsCheck: |
434 | 0 | return "ConstraintsCheck"; |
435 | 0 | case CodeSynthesisContext::ConstraintSubstitution: |
436 | 0 | return "ConstraintSubstitution"; |
437 | 0 | case CodeSynthesisContext::ConstraintNormalization: |
438 | 0 | return "ConstraintNormalization"; |
439 | 0 | case CodeSynthesisContext::ParameterMappingSubstitution: |
440 | 0 | return "ParameterMappingSubstitution"; |
441 | 0 | case CodeSynthesisContext::RequirementInstantiation: |
442 | 0 | return "RequirementInstantiation"; |
443 | 0 | case CodeSynthesisContext::NestedRequirementConstraintsCheck: |
444 | 0 | return "NestedRequirementConstraintsCheck"; |
445 | 0 | case CodeSynthesisContext::InitializingStructuredBinding: |
446 | 0 | return "InitializingStructuredBinding"; |
447 | 0 | case CodeSynthesisContext::MarkingClassDllexported: |
448 | 0 | return "MarkingClassDllexported"; |
449 | 0 | } |
450 | 0 | return ""; |
451 | 0 | } |
452 | | |
453 | | template <bool BeginInstantiation> |
454 | | static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema, |
455 | 152 | const CodeSynthesisContext &Inst) { |
456 | 152 | std::string YAML; |
457 | 152 | { |
458 | 152 | llvm::raw_string_ostream OS(YAML); |
459 | 152 | llvm::yaml::Output YO(OS); |
460 | 152 | TemplightEntry Entry = |
461 | 152 | getTemplightEntry<BeginInstantiation>(TheSema, Inst); |
462 | 152 | llvm::yaml::EmptyContext Context; |
463 | 152 | llvm::yaml::yamlize(YO, Entry, true, Context); |
464 | 152 | } |
465 | 152 | Out << "---" << YAML << "\n"; |
466 | 152 | } FrontendActions.cpp:void (anonymous namespace)::DefaultTemplateInstCallback::displayTemplightEntry<true>(llvm::raw_ostream&, clang::Sema const&, clang::Sema::CodeSynthesisContext const&) Line | Count | Source | 455 | 76 | const CodeSynthesisContext &Inst) { | 456 | 76 | std::string YAML; | 457 | 76 | { | 458 | 76 | llvm::raw_string_ostream OS(YAML); | 459 | 76 | llvm::yaml::Output YO(OS); | 460 | 76 | TemplightEntry Entry = | 461 | 76 | getTemplightEntry<BeginInstantiation>(TheSema, Inst); | 462 | 76 | llvm::yaml::EmptyContext Context; | 463 | 76 | llvm::yaml::yamlize(YO, Entry, true, Context); | 464 | 76 | } | 465 | 76 | Out << "---" << YAML << "\n"; | 466 | 76 | } |
FrontendActions.cpp:void (anonymous namespace)::DefaultTemplateInstCallback::displayTemplightEntry<false>(llvm::raw_ostream&, clang::Sema const&, clang::Sema::CodeSynthesisContext const&) Line | Count | Source | 455 | 76 | const CodeSynthesisContext &Inst) { | 456 | 76 | std::string YAML; | 457 | 76 | { | 458 | 76 | llvm::raw_string_ostream OS(YAML); | 459 | 76 | llvm::yaml::Output YO(OS); | 460 | 76 | TemplightEntry Entry = | 461 | 76 | getTemplightEntry<BeginInstantiation>(TheSema, Inst); | 462 | 76 | llvm::yaml::EmptyContext Context; | 463 | 76 | llvm::yaml::yamlize(YO, Entry, true, Context); | 464 | 76 | } | 465 | 76 | Out << "---" << YAML << "\n"; | 466 | 76 | } |
|
467 | | |
468 | | template <bool BeginInstantiation> |
469 | | static TemplightEntry getTemplightEntry(const Sema &TheSema, |
470 | 152 | const CodeSynthesisContext &Inst) { |
471 | 152 | TemplightEntry Entry; |
472 | 152 | Entry.Kind = toString(Inst.Kind); |
473 | 76 | Entry.Event = BeginInstantiation ? "Begin" : "End"; |
474 | 152 | if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { |
475 | 152 | llvm::raw_string_ostream OS(Entry.Name); |
476 | 152 | PrintingPolicy Policy = TheSema.Context.getPrintingPolicy(); |
477 | | // FIXME: Also ask for FullyQualifiedNames? |
478 | 152 | Policy.SuppressDefaultTemplateArgs = false; |
479 | 152 | NamedTemplate->getNameForDiagnostic(OS, Policy, true); |
480 | 152 | const PresumedLoc DefLoc = |
481 | 152 | TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); |
482 | 152 | if(!DefLoc.isInvalid()) |
483 | 152 | Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + |
484 | 152 | std::to_string(DefLoc.getLine()) + ":" + |
485 | 152 | std::to_string(DefLoc.getColumn()); |
486 | 152 | } |
487 | 152 | const PresumedLoc PoiLoc = |
488 | 152 | TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); |
489 | 152 | if (!PoiLoc.isInvalid()) { |
490 | 152 | Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" + |
491 | 152 | std::to_string(PoiLoc.getLine()) + ":" + |
492 | 152 | std::to_string(PoiLoc.getColumn()); |
493 | 152 | } |
494 | 152 | return Entry; |
495 | 152 | } FrontendActions.cpp:(anonymous namespace)::TemplightEntry (anonymous namespace)::DefaultTemplateInstCallback::getTemplightEntry<true>(clang::Sema const&, clang::Sema::CodeSynthesisContext const&) Line | Count | Source | 470 | 76 | const CodeSynthesisContext &Inst) { | 471 | 76 | TemplightEntry Entry; | 472 | 76 | Entry.Kind = toString(Inst.Kind); | 473 | 76 | Entry.Event = BeginInstantiation ? "Begin" : "End"0 ; | 474 | 76 | if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { | 475 | 76 | llvm::raw_string_ostream OS(Entry.Name); | 476 | 76 | PrintingPolicy Policy = TheSema.Context.getPrintingPolicy(); | 477 | | // FIXME: Also ask for FullyQualifiedNames? | 478 | 76 | Policy.SuppressDefaultTemplateArgs = false; | 479 | 76 | NamedTemplate->getNameForDiagnostic(OS, Policy, true); | 480 | 76 | const PresumedLoc DefLoc = | 481 | 76 | TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); | 482 | 76 | if(!DefLoc.isInvalid()) | 483 | 76 | Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + | 484 | 76 | std::to_string(DefLoc.getLine()) + ":" + | 485 | 76 | std::to_string(DefLoc.getColumn()); | 486 | 76 | } | 487 | 76 | const PresumedLoc PoiLoc = | 488 | 76 | TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); | 489 | 76 | if (!PoiLoc.isInvalid()) { | 490 | 76 | Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" + | 491 | 76 | std::to_string(PoiLoc.getLine()) + ":" + | 492 | 76 | std::to_string(PoiLoc.getColumn()); | 493 | 76 | } | 494 | 76 | return Entry; | 495 | 76 | } |
FrontendActions.cpp:(anonymous namespace)::TemplightEntry (anonymous namespace)::DefaultTemplateInstCallback::getTemplightEntry<false>(clang::Sema const&, clang::Sema::CodeSynthesisContext const&) Line | Count | Source | 470 | 76 | const CodeSynthesisContext &Inst) { | 471 | 76 | TemplightEntry Entry; | 472 | 76 | Entry.Kind = toString(Inst.Kind); | 473 | 76 | Entry.Event = BeginInstantiation ? "Begin"0 : "End"; | 474 | 76 | if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { | 475 | 76 | llvm::raw_string_ostream OS(Entry.Name); | 476 | 76 | PrintingPolicy Policy = TheSema.Context.getPrintingPolicy(); | 477 | | // FIXME: Also ask for FullyQualifiedNames? | 478 | 76 | Policy.SuppressDefaultTemplateArgs = false; | 479 | 76 | NamedTemplate->getNameForDiagnostic(OS, Policy, true); | 480 | 76 | const PresumedLoc DefLoc = | 481 | 76 | TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); | 482 | 76 | if(!DefLoc.isInvalid()) | 483 | 76 | Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + | 484 | 76 | std::to_string(DefLoc.getLine()) + ":" + | 485 | 76 | std::to_string(DefLoc.getColumn()); | 486 | 76 | } | 487 | 76 | const PresumedLoc PoiLoc = | 488 | 76 | TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); | 489 | 76 | if (!PoiLoc.isInvalid()) { | 490 | 76 | Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" + | 491 | 76 | std::to_string(PoiLoc.getLine()) + ":" + | 492 | 76 | std::to_string(PoiLoc.getColumn()); | 493 | 76 | } | 494 | 76 | return Entry; | 495 | 76 | } |
|
496 | | }; |
497 | | } // namespace |
498 | | |
499 | | std::unique_ptr<ASTConsumer> |
500 | 11 | TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
501 | 11 | return std::make_unique<ASTConsumer>(); |
502 | 11 | } |
503 | | |
504 | 11 | void TemplightDumpAction::ExecuteAction() { |
505 | 11 | CompilerInstance &CI = getCompilerInstance(); |
506 | | |
507 | | // This part is normally done by ASTFrontEndAction, but needs to happen |
508 | | // before Templight observers can be created |
509 | | // FIXME: Move the truncation aspect of this into Sema, we delayed this till |
510 | | // here so the source manager would be initialized. |
511 | 11 | EnsureSemaIsCreated(CI, *this); |
512 | | |
513 | 11 | CI.getSema().TemplateInstCallbacks.push_back( |
514 | 11 | std::make_unique<DefaultTemplateInstCallback>()); |
515 | 11 | ASTFrontendAction::ExecuteAction(); |
516 | 11 | } |
517 | | |
518 | | namespace { |
519 | | /// AST reader listener that dumps module information for a module |
520 | | /// file. |
521 | | class DumpModuleInfoListener : public ASTReaderListener { |
522 | | llvm::raw_ostream &Out; |
523 | | |
524 | | public: |
525 | 5 | DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { } |
526 | | |
527 | | #define DUMP_BOOLEAN(Value, Text) \ |
528 | 915 | Out.indent(4) << Text << ": " << (Value? "Yes"164 : "No"751 ) << "\n" |
529 | | |
530 | 5 | bool ReadFullVersionInformation(StringRef FullVersion) override { |
531 | 5 | Out.indent(2) |
532 | 5 | << "Generated by " |
533 | 5 | << (FullVersion == getClangFullRepositoryVersion()? "this" |
534 | 0 | : "a different") |
535 | 5 | << " Clang: " << FullVersion << "\n"; |
536 | 5 | return ASTReaderListener::ReadFullVersionInformation(FullVersion); |
537 | 5 | } |
538 | | |
539 | 5 | void ReadModuleName(StringRef ModuleName) override { |
540 | 5 | Out.indent(2) << "Module name: " << ModuleName << "\n"; |
541 | 5 | } |
542 | 5 | void ReadModuleMapFile(StringRef ModuleMapPath) override { |
543 | 5 | Out.indent(2) << "Module map file: " << ModuleMapPath << "\n"; |
544 | 5 | } |
545 | | |
546 | | bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, |
547 | 5 | bool AllowCompatibleDifferences) override { |
548 | 5 | Out.indent(2) << "Language options:\n"; |
549 | 5 | #define LANGOPT(Name, Bits, Default, Description) \ |
550 | 775 | DUMP_BOOLEAN(LangOpts.Name, Description); |
551 | 5 | #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ |
552 | 105 | Out.indent(4) << Description << ": " \ |
553 | 105 | << static_cast<unsigned>(LangOpts.get##Name()) << "\n"; |
554 | 5 | #define VALUE_LANGOPT(Name, Bits, Default, Description) \ |
555 | 60 | Out.indent(4) << Description << ": " << LangOpts.Name << "\n"; |
556 | 5 | #define BENIGN_LANGOPT(Name, Bits, Default, Description) |
557 | 5 | #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) |
558 | 5 | #include "clang/Basic/LangOptions.def" |
559 | | |
560 | 5 | if (!LangOpts.ModuleFeatures.empty()) { |
561 | 4 | Out.indent(4) << "Module features:\n"; |
562 | 4 | for (StringRef Feature : LangOpts.ModuleFeatures) |
563 | 4 | Out.indent(6) << Feature << "\n"; |
564 | 4 | } |
565 | | |
566 | 5 | return false; |
567 | 5 | } |
568 | | |
569 | | bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, |
570 | 5 | bool AllowCompatibleDifferences) override { |
571 | 5 | Out.indent(2) << "Target options:\n"; |
572 | 5 | Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n"; |
573 | 5 | Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n"; |
574 | 5 | Out.indent(4) << " TuneCPU: " << TargetOpts.TuneCPU << "\n"; |
575 | 5 | Out.indent(4) << " ABI: " << TargetOpts.ABI << "\n"; |
576 | | |
577 | 5 | if (!TargetOpts.FeaturesAsWritten.empty()) { |
578 | 0 | Out.indent(4) << "Target features:\n"; |
579 | 0 | for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); |
580 | 0 | I != N; ++I) { |
581 | 0 | Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n"; |
582 | 0 | } |
583 | 0 | } |
584 | | |
585 | 5 | return false; |
586 | 5 | } |
587 | | |
588 | | bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, |
589 | 5 | bool Complain) override { |
590 | 5 | Out.indent(2) << "Diagnostic options:\n"; |
591 | 110 | #define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name); |
592 | 5 | #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ |
593 | 15 | Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n"; |
594 | 5 | #define VALUE_DIAGOPT(Name, Bits, Default) \ |
595 | 45 | Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n"; |
596 | 5 | #include "clang/Basic/DiagnosticOptions.def" |
597 | | |
598 | 5 | Out.indent(4) << "Diagnostic flags:\n"; |
599 | 5 | for (const std::string &Warning : DiagOpts->Warnings) |
600 | 4 | Out.indent(6) << "-W" << Warning << "\n"; |
601 | 5 | for (const std::string &Remark : DiagOpts->Remarks) |
602 | 0 | Out.indent(6) << "-R" << Remark << "\n"; |
603 | | |
604 | 5 | return false; |
605 | 5 | } |
606 | | |
607 | | bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, |
608 | | StringRef SpecificModuleCachePath, |
609 | 5 | bool Complain) override { |
610 | 5 | Out.indent(2) << "Header search options:\n"; |
611 | 5 | Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n"; |
612 | 5 | Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n"; |
613 | 5 | Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n"; |
614 | 5 | DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes, |
615 | 5 | "Use builtin include directories [-nobuiltininc]"); |
616 | 5 | DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes, |
617 | 5 | "Use standard system include directories [-nostdinc]"); |
618 | 5 | DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes, |
619 | 5 | "Use standard C++ include directories [-nostdinc++]"); |
620 | 5 | DUMP_BOOLEAN(HSOpts.UseLibcxx, |
621 | 5 | "Use libc++ (rather than libstdc++) [-stdlib=]"); |
622 | 5 | return false; |
623 | 5 | } |
624 | | |
625 | | bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, |
626 | | bool Complain, |
627 | 5 | std::string &SuggestedPredefines) override { |
628 | 5 | Out.indent(2) << "Preprocessor options:\n"; |
629 | 5 | DUMP_BOOLEAN(PPOpts.UsePredefines, |
630 | 5 | "Uses compiler/target-specific predefines [-undef]"); |
631 | 5 | DUMP_BOOLEAN(PPOpts.DetailedRecord, |
632 | 5 | "Uses detailed preprocessing record (for indexing)"); |
633 | | |
634 | 5 | if (!PPOpts.Macros.empty()) { |
635 | 4 | Out.indent(4) << "Predefined macros:\n"; |
636 | 4 | } |
637 | | |
638 | 5 | for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator |
639 | 5 | I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end(); |
640 | 13 | I != IEnd; ++I8 ) { |
641 | 8 | Out.indent(6); |
642 | 8 | if (I->second) |
643 | 0 | Out << "-U"; |
644 | 8 | else |
645 | 8 | Out << "-D"; |
646 | 8 | Out << I->first << "\n"; |
647 | 8 | } |
648 | 5 | return false; |
649 | 5 | } |
650 | | |
651 | | /// Indicates that a particular module file extension has been read. |
652 | | void readModuleFileExtension( |
653 | 2 | const ModuleFileExtensionMetadata &Metadata) override { |
654 | 2 | Out.indent(2) << "Module file extension '" |
655 | 2 | << Metadata.BlockName << "' " << Metadata.MajorVersion |
656 | 2 | << "." << Metadata.MinorVersion; |
657 | 2 | if (!Metadata.UserInfo.empty()) { |
658 | 2 | Out << ": "; |
659 | 2 | Out.write_escaped(Metadata.UserInfo); |
660 | 2 | } |
661 | | |
662 | 2 | Out << "\n"; |
663 | 2 | } |
664 | | |
665 | | /// Tells the \c ASTReaderListener that we want to receive the |
666 | | /// input files of the AST file via \c visitInputFile. |
667 | 5 | bool needsInputFileVisitation() override { return true; } |
668 | | |
669 | | /// Tells the \c ASTReaderListener that we want to receive the |
670 | | /// input files of the AST file via \c visitInputFile. |
671 | 5 | bool needsSystemInputFileVisitation() override { return true; } |
672 | | |
673 | | /// Indicates that the AST file contains particular input file. |
674 | | /// |
675 | | /// \returns true to continue receiving the next input file, false to stop. |
676 | | bool visitInputFile(StringRef Filename, bool isSystem, |
677 | 42 | bool isOverridden, bool isExplicitModule) override { |
678 | | |
679 | 42 | Out.indent(2) << "Input file: " << Filename; |
680 | | |
681 | 42 | if (isSystem || isOverridden || isExplicitModule) { |
682 | 0 | Out << " ["; |
683 | 0 | if (isSystem) { |
684 | 0 | Out << "System"; |
685 | 0 | if (isOverridden || isExplicitModule) |
686 | 0 | Out << ", "; |
687 | 0 | } |
688 | 0 | if (isOverridden) { |
689 | 0 | Out << "Overridden"; |
690 | 0 | if (isExplicitModule) |
691 | 0 | Out << ", "; |
692 | 0 | } |
693 | 0 | if (isExplicitModule) |
694 | 0 | Out << "ExplicitModule"; |
695 | |
|
696 | 0 | Out << "]"; |
697 | 0 | } |
698 | | |
699 | 42 | Out << "\n"; |
700 | | |
701 | 42 | return true; |
702 | 42 | } |
703 | | |
704 | | /// Returns true if this \c ASTReaderListener wants to receive the |
705 | | /// imports of the AST file via \c visitImport, false otherwise. |
706 | 5 | bool needsImportVisitation() const override { return true; } |
707 | | |
708 | | /// If needsImportVisitation returns \c true, this is called for each |
709 | | /// AST file imported by this AST file. |
710 | 4 | void visitImport(StringRef ModuleName, StringRef Filename) override { |
711 | 4 | Out.indent(2) << "Imports module '" << ModuleName |
712 | 4 | << "': " << Filename.str() << "\n"; |
713 | 4 | } |
714 | | #undef DUMP_BOOLEAN |
715 | | }; |
716 | | } |
717 | | |
718 | 5 | bool DumpModuleInfoAction::BeginInvocation(CompilerInstance &CI) { |
719 | | // The Object file reader also supports raw ast files and there is no point in |
720 | | // being strict about the module file format in -module-file-info mode. |
721 | 5 | CI.getHeaderSearchOpts().ModuleFormat = "obj"; |
722 | 5 | return true; |
723 | 5 | } |
724 | | |
725 | 5 | void DumpModuleInfoAction::ExecuteAction() { |
726 | | // Set up the output file. |
727 | 5 | std::unique_ptr<llvm::raw_fd_ostream> OutFile; |
728 | 5 | StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile; |
729 | 5 | if (!OutputFileName.empty() && OutputFileName != "-"0 ) { |
730 | 0 | std::error_code EC; |
731 | 0 | OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC, |
732 | 0 | llvm::sys::fs::OF_Text)); |
733 | 0 | } |
734 | 5 | llvm::raw_ostream &Out = OutFile.get()? *OutFile.get()0 : llvm::outs(); |
735 | | |
736 | 5 | Out << "Information for module file '" << getCurrentFile() << "':\n"; |
737 | 5 | auto &FileMgr = getCompilerInstance().getFileManager(); |
738 | 5 | auto Buffer = FileMgr.getBufferForFile(getCurrentFile()); |
739 | 5 | StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer(); |
740 | 5 | bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P'3 && |
741 | 3 | Magic[2] == 'C' && Magic[3] == 'H'); |
742 | 3 | Out << " Module format: " << (IsRaw ? "raw" : "obj"2 ) << "\n"; |
743 | | |
744 | 5 | Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
745 | 5 | DumpModuleInfoListener Listener(Out); |
746 | 5 | HeaderSearchOptions &HSOpts = |
747 | 5 | PP.getHeaderSearchInfo().getHeaderSearchOpts(); |
748 | 5 | ASTReader::readASTFileControlBlock( |
749 | 5 | getCurrentFile(), FileMgr, getCompilerInstance().getPCHContainerReader(), |
750 | 5 | /*FindModuleFileExtensions=*/true, Listener, |
751 | 5 | HSOpts.ModulesValidateDiagnosticOptions); |
752 | 5 | } |
753 | | |
754 | | //===----------------------------------------------------------------------===// |
755 | | // Preprocessor Actions |
756 | | //===----------------------------------------------------------------------===// |
757 | | |
758 | 0 | void DumpRawTokensAction::ExecuteAction() { |
759 | 0 | Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
760 | 0 | SourceManager &SM = PP.getSourceManager(); |
761 | | |
762 | | // Start lexing the specified input file. |
763 | 0 | llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID()); |
764 | 0 | Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); |
765 | 0 | RawLex.SetKeepWhitespaceMode(true); |
766 | |
|
767 | 0 | Token RawTok; |
768 | 0 | RawLex.LexFromRawLexer(RawTok); |
769 | 0 | while (RawTok.isNot(tok::eof)) { |
770 | 0 | PP.DumpToken(RawTok, true); |
771 | 0 | llvm::errs() << "\n"; |
772 | 0 | RawLex.LexFromRawLexer(RawTok); |
773 | 0 | } |
774 | 0 | } |
775 | | |
776 | 3 | void DumpTokensAction::ExecuteAction() { |
777 | 3 | Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
778 | | // Start preprocessing the specified input file. |
779 | 3 | Token Tok; |
780 | 3 | PP.EnterMainSourceFile(); |
781 | 7 | do { |
782 | 7 | PP.Lex(Tok); |
783 | 7 | PP.DumpToken(Tok, true); |
784 | 7 | llvm::errs() << "\n"; |
785 | 7 | } while (Tok.isNot(tok::eof)); |
786 | 3 | } |
787 | | |
788 | 126 | void PreprocessOnlyAction::ExecuteAction() { |
789 | 126 | Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
790 | | |
791 | | // Ignore unknown pragmas. |
792 | 126 | PP.IgnorePragmas(); |
793 | | |
794 | 126 | Token Tok; |
795 | | // Start parsing the specified input file. |
796 | 126 | PP.EnterMainSourceFile(); |
797 | 579 | do { |
798 | 579 | PP.Lex(Tok); |
799 | 579 | } while (Tok.isNot(tok::eof)); |
800 | 126 | } |
801 | | |
802 | 1.94k | void PrintPreprocessedAction::ExecuteAction() { |
803 | 1.94k | CompilerInstance &CI = getCompilerInstance(); |
804 | | // Output file may need to be set to 'Binary', to avoid converting Unix style |
805 | | // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). |
806 | | // |
807 | | // Look to see what type of line endings the file uses. If there's a |
808 | | // CRLF, then we won't open the file up in binary mode. If there is |
809 | | // just an LF or CR, then we will open the file up in binary mode. |
810 | | // In this fashion, the output format should match the input format, unless |
811 | | // the input format has inconsistent line endings. |
812 | | // |
813 | | // This should be a relatively fast operation since most files won't have |
814 | | // all of their source code on a single line. However, that is still a |
815 | | // concern, so if we scan for too long, we'll just assume the file should |
816 | | // be opened in binary mode. |
817 | 1.94k | bool BinaryMode = true; |
818 | 1.94k | const SourceManager& SM = CI.getSourceManager(); |
819 | 1.94k | if (llvm::Optional<llvm::MemoryBufferRef> Buffer = |
820 | 1.94k | SM.getBufferOrNone(SM.getMainFileID())) { |
821 | 1.94k | const char *cur = Buffer->getBufferStart(); |
822 | 1.94k | const char *end = Buffer->getBufferEnd(); |
823 | 1.59k | const char *next = (cur != end) ? cur + 1 : end345 ; |
824 | | |
825 | | // Limit ourselves to only scanning 256 characters into the source |
826 | | // file. This is mostly a sanity check in case the file has no |
827 | | // newlines whatsoever. |
828 | 1.94k | if (end - cur > 256) end = cur + 2561.50k ; |
829 | | |
830 | 124k | while (next < end) { |
831 | 124k | if (*cur == 0x0D) { // CR |
832 | 3 | if (*next == 0x0A) // CRLF |
833 | 3 | BinaryMode = false; |
834 | | |
835 | 3 | break; |
836 | 124k | } else if (*cur == 0x0A) // LF |
837 | 1.59k | break; |
838 | | |
839 | 122k | ++cur; |
840 | 122k | ++next; |
841 | 122k | } |
842 | 1.94k | } |
843 | | |
844 | 1.94k | std::unique_ptr<raw_ostream> OS = |
845 | 1.94k | CI.createDefaultOutputFile(BinaryMode, getCurrentFileOrBufferName()); |
846 | 1.94k | if (!OS) return1 ; |
847 | | |
848 | | // If we're preprocessing a module map, start by dumping the contents of the |
849 | | // module itself before switching to the input buffer. |
850 | 1.94k | auto &Input = getCurrentInput(); |
851 | 1.94k | if (Input.getKind().getFormat() == InputKind::ModuleMap) { |
852 | 5 | if (Input.isFile()) { |
853 | 5 | (*OS) << "# 1 \""; |
854 | 5 | OS->write_escaped(Input.getFile()); |
855 | 5 | (*OS) << "\"\n"; |
856 | 5 | } |
857 | 5 | getCurrentModule()->print(*OS); |
858 | 5 | (*OS) << "#pragma clang module contents\n"; |
859 | 5 | } |
860 | | |
861 | 1.94k | DoPrintPreprocessedInput(CI.getPreprocessor(), OS.get(), |
862 | 1.94k | CI.getPreprocessorOutputOpts()); |
863 | 1.94k | } |
864 | | |
865 | 2 | void PrintPreambleAction::ExecuteAction() { |
866 | 2 | switch (getCurrentFileKind().getLanguage()) { |
867 | 2 | case Language::C: |
868 | 2 | case Language::CXX: |
869 | 2 | case Language::ObjC: |
870 | 2 | case Language::ObjCXX: |
871 | 2 | case Language::OpenCL: |
872 | 2 | case Language::CUDA: |
873 | 2 | case Language::HIP: |
874 | 2 | break; |
875 | | |
876 | 0 | case Language::Unknown: |
877 | 0 | case Language::Asm: |
878 | 0 | case Language::LLVM_IR: |
879 | 0 | case Language::RenderScript: |
880 | | // We can't do anything with these. |
881 | 0 | return; |
882 | 2 | } |
883 | | |
884 | | // We don't expect to find any #include directives in a preprocessed input. |
885 | 2 | if (getCurrentFileKind().isPreprocessed()) |
886 | 0 | return; |
887 | | |
888 | 2 | CompilerInstance &CI = getCompilerInstance(); |
889 | 2 | auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); |
890 | 2 | if (Buffer) { |
891 | 2 | unsigned Preamble = |
892 | 2 | Lexer::ComputePreamble((*Buffer)->getBuffer(), CI.getLangOpts()).Size; |
893 | 2 | llvm::outs().write((*Buffer)->getBufferStart(), Preamble); |
894 | 2 | } |
895 | 2 | } |
896 | | |
897 | 3 | void DumpCompilerOptionsAction::ExecuteAction() { |
898 | 3 | CompilerInstance &CI = getCompilerInstance(); |
899 | 3 | std::unique_ptr<raw_ostream> OSP = |
900 | 3 | CI.createDefaultOutputFile(false, getCurrentFile()); |
901 | 3 | if (!OSP) |
902 | 0 | return; |
903 | | |
904 | 3 | raw_ostream &OS = *OSP; |
905 | 3 | const Preprocessor &PP = CI.getPreprocessor(); |
906 | 3 | const LangOptions &LangOpts = PP.getLangOpts(); |
907 | | |
908 | | // FIXME: Rather than manually format the JSON (which is awkward due to |
909 | | // needing to remove trailing commas), this should make use of a JSON library. |
910 | | // FIXME: Instead of printing enums as an integral value and specifying the |
911 | | // type as a separate field, use introspection to print the enumerator. |
912 | | |
913 | 3 | OS << "{\n"; |
914 | 3 | OS << "\n\"features\" : [\n"; |
915 | 3 | { |
916 | 3 | llvm::SmallString<128> Str; |
917 | 3 | #define FEATURE(Name, Predicate) \ |
918 | 489 | ("\t{\"" #Name "\" : " + llvm::Twine(Predicate25 ? "true"246 : "false"243 ) + "},\n") \ |
919 | 489 | .toVector(Str); |
920 | 3 | #include "clang/Basic/Features.def" |
921 | 3 | #undef FEATURE |
922 | | // Remove the newline and comma from the last entry to ensure this remains |
923 | | // valid JSON. |
924 | 3 | OS << Str.substr(0, Str.size() - 2); |
925 | 3 | } |
926 | 3 | OS << "\n],\n"; |
927 | | |
928 | 3 | OS << "\n\"extensions\" : [\n"; |
929 | 3 | { |
930 | 3 | llvm::SmallString<128> Str; |
931 | 3 | #define EXTENSION(Name, Predicate) \ |
932 | 84 | ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true"67 : "false"17 ) + "},\n") \ |
933 | 84 | .toVector(Str); |
934 | 3 | #include "clang/Basic/Features.def" |
935 | 3 | #undef EXTENSION |
936 | | // Remove the newline and comma from the last entry to ensure this remains |
937 | | // valid JSON. |
938 | 3 | OS << Str.substr(0, Str.size() - 2); |
939 | 3 | } |
940 | 3 | OS << "\n]\n"; |
941 | | |
942 | 3 | OS << "}"; |
943 | 3 | } |
944 | | |
945 | 7 | void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { |
946 | 7 | CompilerInstance &CI = getCompilerInstance(); |
947 | 7 | SourceManager &SM = CI.getPreprocessor().getSourceManager(); |
948 | 7 | llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID()); |
949 | | |
950 | 7 | llvm::SmallString<1024> Output; |
951 | 7 | llvm::SmallVector<minimize_source_to_dependency_directives::Token, 32> Toks; |
952 | 7 | if (minimizeSourceToDependencyDirectives( |
953 | 7 | FromFile.getBuffer(), Output, Toks, &CI.getDiagnostics(), |
954 | 3 | SM.getLocForStartOfFile(SM.getMainFileID()))) { |
955 | 3 | assert(CI.getDiagnostics().hasErrorOccurred() && |
956 | 3 | "no errors reported for failure"); |
957 | | |
958 | | // Preprocess the source when verifying the diagnostics to capture the |
959 | | // 'expected' comments. |
960 | 3 | if (CI.getDiagnosticOpts().VerifyDiagnostics) { |
961 | | // Make sure we don't emit new diagnostics! |
962 | 3 | CI.getDiagnostics().setSuppressAllDiagnostics(true); |
963 | 3 | Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
964 | 3 | PP.EnterMainSourceFile(); |
965 | 3 | Token Tok; |
966 | 11 | do { |
967 | 11 | PP.Lex(Tok); |
968 | 11 | } while (Tok.isNot(tok::eof)); |
969 | 3 | } |
970 | 3 | return; |
971 | 3 | } |
972 | 4 | llvm::outs() << Output; |
973 | 4 | } |