1 | //===- Diagnostic.h - C Language Family Diagnostic Handling -----*- C++ -*-===// |
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 | /// \file |
10 | /// Defines the Diagnostic-related interfaces. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H |
15 | #define LLVM_CLANG_BASIC_DIAGNOSTIC_H |
16 | |
17 | #include "clang/Basic/DiagnosticIDs.h" |
18 | #include "clang/Basic/DiagnosticOptions.h" |
19 | #include "clang/Basic/SourceLocation.h" |
20 | #include "clang/Basic/Specifiers.h" |
21 | #include "llvm/ADT/ArrayRef.h" |
22 | #include "llvm/ADT/DenseMap.h" |
23 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
24 | #include "llvm/ADT/SmallVector.h" |
25 | #include "llvm/ADT/StringRef.h" |
26 | #include "llvm/ADT/iterator_range.h" |
27 | #include "llvm/Support/Compiler.h" |
28 | #include <cassert> |
29 | #include <cstdint> |
30 | #include <limits> |
31 | #include <list> |
32 | #include <map> |
33 | #include <memory> |
34 | #include <optional> |
35 | #include <string> |
36 | #include <type_traits> |
37 | #include <utility> |
38 | #include <vector> |
39 | |
40 | namespace llvm { |
41 | class Error; |
42 | class raw_ostream; |
43 | } // namespace llvm |
44 | |
45 | namespace clang { |
46 | |
47 | class DeclContext; |
48 | class DiagnosticBuilder; |
49 | class DiagnosticConsumer; |
50 | class IdentifierInfo; |
51 | class LangOptions; |
52 | class Preprocessor; |
53 | class SourceManager; |
54 | class StoredDiagnostic; |
55 | |
56 | namespace tok { |
57 | |
58 | enum TokenKind : unsigned short; |
59 | |
60 | } // namespace tok |
61 | |
62 | /// Annotates a diagnostic with some code that should be |
63 | /// inserted, removed, or replaced to fix the problem. |
64 | /// |
65 | /// This kind of hint should be used when we are certain that the |
66 | /// introduction, removal, or modification of a particular (small!) |
67 | /// amount of code will correct a compilation error. The compiler |
68 | /// should also provide full recovery from such errors, such that |
69 | /// suppressing the diagnostic output can still result in successful |
70 | /// compilation. |
71 | class FixItHint { |
72 | public: |
73 | /// Code that should be replaced to correct the error. Empty for an |
74 | /// insertion hint. |
75 | CharSourceRange RemoveRange; |
76 | |
77 | /// Code in the specific range that should be inserted in the insertion |
78 | /// location. |
79 | CharSourceRange InsertFromRange; |
80 | |
81 | /// The actual code to insert at the insertion location, as a |
82 | /// string. |
83 | std::string CodeToInsert; |
84 | |
85 | bool BeforePreviousInsertions = false; |
86 | |
87 | /// Empty code modification hint, indicating that no code |
88 | /// modification is known. |
89 | FixItHint() = default; |
90 | |
91 | bool isNull() const { |
92 | return !RemoveRange.isValid(); |
93 | } |
94 | |
95 | /// Create a code modification hint that inserts the given |
96 | /// code string at a specific location. |
97 | static FixItHint CreateInsertion(SourceLocation InsertionLoc, |
98 | StringRef Code, |
99 | bool BeforePreviousInsertions = false) { |
100 | FixItHint Hint; |
101 | Hint.RemoveRange = |
102 | CharSourceRange::getCharRange(B: InsertionLoc, E: InsertionLoc); |
103 | Hint.CodeToInsert = std::string(Code); |
104 | Hint.BeforePreviousInsertions = BeforePreviousInsertions; |
105 | return Hint; |
106 | } |
107 | |
108 | /// Create a code modification hint that inserts the given |
109 | /// code from \p FromRange at a specific location. |
110 | static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, |
111 | CharSourceRange FromRange, |
112 | bool BeforePreviousInsertions = false) { |
113 | FixItHint Hint; |
114 | Hint.RemoveRange = |
115 | CharSourceRange::getCharRange(B: InsertionLoc, E: InsertionLoc); |
116 | Hint.InsertFromRange = FromRange; |
117 | Hint.BeforePreviousInsertions = BeforePreviousInsertions; |
118 | return Hint; |
119 | } |
120 | |
121 | /// Create a code modification hint that removes the given |
122 | /// source range. |
123 | static FixItHint CreateRemoval(CharSourceRange RemoveRange) { |
124 | FixItHint Hint; |
125 | Hint.RemoveRange = RemoveRange; |
126 | return Hint; |
127 | } |
128 | static FixItHint CreateRemoval(SourceRange RemoveRange) { |
129 | return CreateRemoval(RemoveRange: CharSourceRange::getTokenRange(R: RemoveRange)); |
130 | } |
131 | |
132 | /// Create a code modification hint that replaces the given |
133 | /// source range with the given code string. |
134 | static FixItHint CreateReplacement(CharSourceRange RemoveRange, |
135 | StringRef Code) { |
136 | FixItHint Hint; |
137 | Hint.RemoveRange = RemoveRange; |
138 | Hint.CodeToInsert = std::string(Code); |
139 | return Hint; |
140 | } |
141 | |
142 | static FixItHint CreateReplacement(SourceRange RemoveRange, |
143 | StringRef Code) { |
144 | return CreateReplacement(RemoveRange: CharSourceRange::getTokenRange(R: RemoveRange), Code); |
145 | } |
146 | }; |
147 | |
148 | struct DiagnosticStorage { |
149 | enum { |
150 | /// The maximum number of arguments we can hold. We |
151 | /// currently only support up to 10 arguments (%0-%9). |
152 | /// |
153 | /// A single diagnostic with more than that almost certainly has to |
154 | /// be simplified anyway. |
155 | MaxArguments = 10 |
156 | }; |
157 | |
158 | /// The number of entries in Arguments. |
159 | unsigned char NumDiagArgs = 0; |
160 | |
161 | /// Specifies for each argument whether it is in DiagArgumentsStr |
162 | /// or in DiagArguments. |
163 | unsigned char DiagArgumentsKind[MaxArguments]; |
164 | |
165 | /// The values for the various substitution positions. |
166 | /// |
167 | /// This is used when the argument is not an std::string. The specific value |
168 | /// is mangled into an uint64_t and the interpretation depends on exactly |
169 | /// what sort of argument kind it is. |
170 | uint64_t DiagArgumentsVal[MaxArguments]; |
171 | |
172 | /// The values for the various substitution positions that have |
173 | /// string arguments. |
174 | std::string DiagArgumentsStr[MaxArguments]; |
175 | |
176 | /// The list of ranges added to this diagnostic. |
177 | SmallVector<CharSourceRange, 8> DiagRanges; |
178 | |
179 | /// If valid, provides a hint with some code to insert, remove, or |
180 | /// modify at a particular position. |
181 | SmallVector<FixItHint, 6> FixItHints; |
182 | |
183 | DiagnosticStorage() = default; |
184 | }; |
185 | |
186 | /// Concrete class used by the front-end to report problems and issues. |
187 | /// |
188 | /// This massages the diagnostics (e.g. handling things like "report warnings |
189 | /// as errors" and passes them off to the DiagnosticConsumer for reporting to |
190 | /// the user. DiagnosticsEngine is tied to one translation unit and one |
191 | /// SourceManager. |
192 | class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { |
193 | public: |
194 | /// The level of the diagnostic, after it has been through mapping. |
195 | enum Level { |
196 | Ignored = DiagnosticIDs::Ignored, |
197 | Note = DiagnosticIDs::Note, |
198 | = DiagnosticIDs::Remark, |
199 | Warning = DiagnosticIDs::Warning, |
200 | Error = DiagnosticIDs::Error, |
201 | Fatal = DiagnosticIDs::Fatal |
202 | }; |
203 | |
204 | enum ArgumentKind { |
205 | /// std::string |
206 | ak_std_string, |
207 | |
208 | /// const char * |
209 | ak_c_string, |
210 | |
211 | /// int |
212 | ak_sint, |
213 | |
214 | /// unsigned |
215 | ak_uint, |
216 | |
217 | /// enum TokenKind : unsigned |
218 | ak_tokenkind, |
219 | |
220 | /// IdentifierInfo |
221 | ak_identifierinfo, |
222 | |
223 | /// address space |
224 | ak_addrspace, |
225 | |
226 | /// Qualifiers |
227 | ak_qual, |
228 | |
229 | /// QualType |
230 | ak_qualtype, |
231 | |
232 | /// DeclarationName |
233 | ak_declarationname, |
234 | |
235 | /// NamedDecl * |
236 | ak_nameddecl, |
237 | |
238 | /// NestedNameSpecifier * |
239 | ak_nestednamespec, |
240 | |
241 | /// DeclContext * |
242 | ak_declcontext, |
243 | |
244 | /// pair<QualType, QualType> |
245 | ak_qualtype_pair, |
246 | |
247 | /// Attr * |
248 | ak_attr |
249 | }; |
250 | |
251 | /// Represents on argument value, which is a union discriminated |
252 | /// by ArgumentKind, with a value. |
253 | using ArgumentValue = std::pair<ArgumentKind, intptr_t>; |
254 | |
255 | private: |
256 | // Used by __extension__ |
257 | unsigned char AllExtensionsSilenced = 0; |
258 | |
259 | // Treat fatal errors like errors. |
260 | bool FatalsAsError = false; |
261 | |
262 | // Suppress all diagnostics. |
263 | bool SuppressAllDiagnostics = false; |
264 | |
265 | // Elide common types of templates. |
266 | bool ElideType = true; |
267 | |
268 | // Print a tree when comparing templates. |
269 | bool PrintTemplateTree = false; |
270 | |
271 | // Color printing is enabled. |
272 | bool ShowColors = false; |
273 | |
274 | // Which overload candidates to show. |
275 | OverloadsShown ShowOverloads = Ovl_All; |
276 | |
277 | // With Ovl_Best, the number of overload candidates to show when we encounter |
278 | // an error. |
279 | // |
280 | // The value here is the number of candidates to show in the first nontrivial |
281 | // error. Future errors may show a different number of candidates. |
282 | unsigned NumOverloadsToShow = 32; |
283 | |
284 | // Cap of # errors emitted, 0 -> no limit. |
285 | unsigned ErrorLimit = 0; |
286 | |
287 | // Cap on depth of template backtrace stack, 0 -> no limit. |
288 | unsigned TemplateBacktraceLimit = 0; |
289 | |
290 | // Cap on depth of constexpr evaluation backtrace stack, 0 -> no limit. |
291 | unsigned ConstexprBacktraceLimit = 0; |
292 | |
293 | IntrusiveRefCntPtr<DiagnosticIDs> Diags; |
294 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; |
295 | DiagnosticConsumer *Client = nullptr; |
296 | std::unique_ptr<DiagnosticConsumer> Owner; |
297 | SourceManager *SourceMgr = nullptr; |
298 | |
299 | /// Mapping information for diagnostics. |
300 | /// |
301 | /// Mapping info is packed into four bits per diagnostic. The low three |
302 | /// bits are the mapping (an instance of diag::Severity), or zero if unset. |
303 | /// The high bit is set when the mapping was established as a user mapping. |
304 | /// If the high bit is clear, then the low bits are set to the default |
305 | /// value, and should be mapped with -pedantic, -Werror, etc. |
306 | /// |
307 | /// A new DiagState is created and kept around when diagnostic pragmas modify |
308 | /// the state so that we know what is the diagnostic state at any given |
309 | /// source location. |
310 | class DiagState { |
311 | llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap; |
312 | |
313 | public: |
314 | // "Global" configuration state that can actually vary between modules. |
315 | |
316 | // Ignore all warnings: -w |
317 | LLVM_PREFERRED_TYPE(bool) |
318 | unsigned IgnoreAllWarnings : 1; |
319 | |
320 | // Enable all warnings. |
321 | LLVM_PREFERRED_TYPE(bool) |
322 | unsigned EnableAllWarnings : 1; |
323 | |
324 | // Treat warnings like errors. |
325 | LLVM_PREFERRED_TYPE(bool) |
326 | unsigned WarningsAsErrors : 1; |
327 | |
328 | // Treat errors like fatal errors. |
329 | LLVM_PREFERRED_TYPE(bool) |
330 | unsigned ErrorsAsFatal : 1; |
331 | |
332 | // Suppress warnings in system headers. |
333 | LLVM_PREFERRED_TYPE(bool) |
334 | unsigned SuppressSystemWarnings : 1; |
335 | |
336 | // Map extensions to warnings or errors? |
337 | diag::Severity ExtBehavior = diag::Severity::Ignored; |
338 | |
339 | DiagState() |
340 | : IgnoreAllWarnings(false), EnableAllWarnings(false), |
341 | WarningsAsErrors(false), ErrorsAsFatal(false), |
342 | SuppressSystemWarnings(false) {} |
343 | |
344 | using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator; |
345 | using const_iterator = |
346 | llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator; |
347 | |
348 | void setMapping(diag::kind Diag, DiagnosticMapping Info) { |
349 | DiagMap[Diag] = Info; |
350 | } |
351 | |
352 | DiagnosticMapping lookupMapping(diag::kind Diag) const { |
353 | return DiagMap.lookup(Val: Diag); |
354 | } |
355 | |
356 | DiagnosticMapping &getOrAddMapping(diag::kind Diag); |
357 | |
358 | const_iterator begin() const { return DiagMap.begin(); } |
359 | const_iterator end() const { return DiagMap.end(); } |
360 | }; |
361 | |
362 | /// Keeps and automatically disposes all DiagStates that we create. |
363 | std::list<DiagState> DiagStates; |
364 | |
365 | /// A mapping from files to the diagnostic states for those files. Lazily |
366 | /// built on demand for files in which the diagnostic state has not changed. |
367 | class DiagStateMap { |
368 | public: |
369 | /// Add an initial diagnostic state. |
370 | void appendFirst(DiagState *State); |
371 | |
372 | /// Add a new latest state point. |
373 | void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State); |
374 | |
375 | /// Look up the diagnostic state at a given source location. |
376 | DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const; |
377 | |
378 | /// Determine whether this map is empty. |
379 | bool empty() const { return Files.empty(); } |
380 | |
381 | /// Clear out this map. |
382 | void clear() { |
383 | Files.clear(); |
384 | FirstDiagState = CurDiagState = nullptr; |
385 | CurDiagStateLoc = SourceLocation(); |
386 | } |
387 | |
388 | /// Produce a debugging dump of the diagnostic state. |
389 | LLVM_DUMP_METHOD void dump(SourceManager &SrcMgr, |
390 | StringRef DiagName = StringRef()) const; |
391 | |
392 | /// Grab the most-recently-added state point. |
393 | DiagState *getCurDiagState() const { return CurDiagState; } |
394 | |
395 | /// Get the location at which a diagnostic state was last added. |
396 | SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; } |
397 | |
398 | private: |
399 | friend class ASTReader; |
400 | friend class ASTWriter; |
401 | |
402 | /// Represents a point in source where the diagnostic state was |
403 | /// modified because of a pragma. |
404 | /// |
405 | /// 'Loc' can be null if the point represents the diagnostic state |
406 | /// modifications done through the command-line. |
407 | struct DiagStatePoint { |
408 | DiagState *State; |
409 | unsigned Offset; |
410 | |
411 | DiagStatePoint(DiagState *State, unsigned Offset) |
412 | : State(State), Offset(Offset) {} |
413 | }; |
414 | |
415 | /// Description of the diagnostic states and state transitions for a |
416 | /// particular FileID. |
417 | struct File { |
418 | /// The diagnostic state for the parent file. This is strictly redundant, |
419 | /// as looking up the DecomposedIncludedLoc for the FileID in the Files |
420 | /// map would give us this, but we cache it here for performance. |
421 | File *Parent = nullptr; |
422 | |
423 | /// The offset of this file within its parent. |
424 | unsigned ParentOffset = 0; |
425 | |
426 | /// Whether this file has any local (not imported from an AST file) |
427 | /// diagnostic state transitions. |
428 | bool HasLocalTransitions = false; |
429 | |
430 | /// The points within the file where the state changes. There will always |
431 | /// be at least one of these (the state on entry to the file). |
432 | llvm::SmallVector<DiagStatePoint, 4> StateTransitions; |
433 | |
434 | DiagState *lookup(unsigned Offset) const; |
435 | }; |
436 | |
437 | /// The diagnostic states for each file. |
438 | mutable std::map<FileID, File> Files; |
439 | |
440 | /// The initial diagnostic state. |
441 | DiagState *FirstDiagState; |
442 | |
443 | /// The current diagnostic state. |
444 | DiagState *CurDiagState; |
445 | |
446 | /// The location at which the current diagnostic state was established. |
447 | SourceLocation CurDiagStateLoc; |
448 | |
449 | /// Get the diagnostic state information for a file. |
450 | File *getFile(SourceManager &SrcMgr, FileID ID) const; |
451 | }; |
452 | |
453 | DiagStateMap DiagStatesByLoc; |
454 | |
455 | /// Keeps the DiagState that was active during each diagnostic 'push' |
456 | /// so we can get back at it when we 'pop'. |
457 | std::vector<DiagState *> DiagStateOnPushStack; |
458 | |
459 | DiagState *GetCurDiagState() const { |
460 | return DiagStatesByLoc.getCurDiagState(); |
461 | } |
462 | |
463 | void PushDiagStatePoint(DiagState *State, SourceLocation L); |
464 | |
465 | /// Finds the DiagStatePoint that contains the diagnostic state of |
466 | /// the given source location. |
467 | DiagState *GetDiagStateForLoc(SourceLocation Loc) const { |
468 | return SourceMgr ? DiagStatesByLoc.lookup(SrcMgr&: *SourceMgr, Loc) |
469 | : DiagStatesByLoc.getCurDiagState(); |
470 | } |
471 | |
472 | /// Sticky flag set to \c true when an error is emitted. |
473 | bool ErrorOccurred; |
474 | |
475 | /// Sticky flag set to \c true when an "uncompilable error" occurs. |
476 | /// I.e. an error that was not upgraded from a warning by -Werror. |
477 | bool UncompilableErrorOccurred; |
478 | |
479 | /// Sticky flag set to \c true when a fatal error is emitted. |
480 | bool FatalErrorOccurred; |
481 | |
482 | /// Indicates that an unrecoverable error has occurred. |
483 | bool UnrecoverableErrorOccurred; |
484 | |
485 | /// Counts for DiagnosticErrorTrap to check whether an error occurred |
486 | /// during a parsing section, e.g. during parsing a function. |
487 | unsigned TrapNumErrorsOccurred; |
488 | unsigned TrapNumUnrecoverableErrorsOccurred; |
489 | |
490 | /// The level of the last diagnostic emitted. |
491 | /// |
492 | /// This is used to emit continuation diagnostics with the same level as the |
493 | /// diagnostic that they follow. |
494 | DiagnosticIDs::Level LastDiagLevel; |
495 | |
496 | /// Number of warnings reported |
497 | unsigned NumWarnings; |
498 | |
499 | /// Number of errors reported |
500 | unsigned NumErrors; |
501 | |
502 | /// A function pointer that converts an opaque diagnostic |
503 | /// argument to a strings. |
504 | /// |
505 | /// This takes the modifiers and argument that was present in the diagnostic. |
506 | /// |
507 | /// The PrevArgs array indicates the previous arguments formatted for this |
508 | /// diagnostic. Implementations of this function can use this information to |
509 | /// avoid redundancy across arguments. |
510 | /// |
511 | /// This is a hack to avoid a layering violation between libbasic and libsema. |
512 | using ArgToStringFnTy = void (*)( |
513 | ArgumentKind Kind, intptr_t Val, |
514 | StringRef Modifier, StringRef Argument, |
515 | ArrayRef<ArgumentValue> PrevArgs, |
516 | SmallVectorImpl<char> &Output, |
517 | void *Cookie, |
518 | ArrayRef<intptr_t> QualTypeVals); |
519 | |
520 | void *ArgToStringCookie = nullptr; |
521 | ArgToStringFnTy ArgToStringFn; |
522 | |
523 | /// ID of the "delayed" diagnostic, which is a (typically |
524 | /// fatal) diagnostic that had to be delayed because it was found |
525 | /// while emitting another diagnostic. |
526 | unsigned DelayedDiagID; |
527 | |
528 | /// First string argument for the delayed diagnostic. |
529 | std::string DelayedDiagArg1; |
530 | |
531 | /// Second string argument for the delayed diagnostic. |
532 | std::string DelayedDiagArg2; |
533 | |
534 | /// Third string argument for the delayed diagnostic. |
535 | std::string DelayedDiagArg3; |
536 | |
537 | /// Optional flag value. |
538 | /// |
539 | /// Some flags accept values, for instance: -Wframe-larger-than=<value> and |
540 | /// -Rpass=<value>. The content of this string is emitted after the flag name |
541 | /// and '='. |
542 | std::string FlagValue; |
543 | |
544 | public: |
545 | explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags, |
546 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, |
547 | DiagnosticConsumer *client = nullptr, |
548 | bool ShouldOwnClient = true); |
549 | DiagnosticsEngine(const DiagnosticsEngine &) = delete; |
550 | DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete; |
551 | ~DiagnosticsEngine(); |
552 | |
553 | friend void DiagnosticsTestHelper(DiagnosticsEngine &); |
554 | LLVM_DUMP_METHOD void dump() const; |
555 | LLVM_DUMP_METHOD void dump(StringRef DiagName) const; |
556 | |
557 | const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { |
558 | return Diags; |
559 | } |
560 | |
561 | /// Retrieve the diagnostic options. |
562 | DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; } |
563 | |
564 | using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>; |
565 | |
566 | /// Get the current set of diagnostic mappings. |
567 | diag_mapping_range getDiagnosticMappings() const { |
568 | const DiagState &DS = *GetCurDiagState(); |
569 | return diag_mapping_range(DS.begin(), DS.end()); |
570 | } |
571 | |
572 | DiagnosticConsumer *getClient() { return Client; } |
573 | const DiagnosticConsumer *getClient() const { return Client; } |
574 | |
575 | /// Determine whether this \c DiagnosticsEngine object own its client. |
576 | bool ownsClient() const { return Owner != nullptr; } |
577 | |
578 | /// Return the current diagnostic client along with ownership of that |
579 | /// client. |
580 | std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); } |
581 | |
582 | bool hasSourceManager() const { return SourceMgr != nullptr; } |
583 | |
584 | SourceManager &getSourceManager() const { |
585 | assert(SourceMgr && "SourceManager not set!" ); |
586 | return *SourceMgr; |
587 | } |
588 | |
589 | void setSourceManager(SourceManager *SrcMgr) { |
590 | assert(DiagStatesByLoc.empty() && |
591 | "Leftover diag state from a different SourceManager." ); |
592 | SourceMgr = SrcMgr; |
593 | } |
594 | |
595 | //===--------------------------------------------------------------------===// |
596 | // DiagnosticsEngine characterization methods, used by a client to customize |
597 | // how diagnostics are emitted. |
598 | // |
599 | |
600 | /// Copies the current DiagMappings and pushes the new copy |
601 | /// onto the top of the stack. |
602 | void pushMappings(SourceLocation Loc); |
603 | |
604 | /// Pops the current DiagMappings off the top of the stack, |
605 | /// causing the new top of the stack to be the active mappings. |
606 | /// |
607 | /// \returns \c true if the pop happens, \c false if there is only one |
608 | /// DiagMapping on the stack. |
609 | bool popMappings(SourceLocation Loc); |
610 | |
611 | /// Set the diagnostic client associated with this diagnostic object. |
612 | /// |
613 | /// \param ShouldOwnClient true if the diagnostic object should take |
614 | /// ownership of \c client. |
615 | void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true); |
616 | |
617 | /// Specify a limit for the number of errors we should |
618 | /// emit before giving up. |
619 | /// |
620 | /// Zero disables the limit. |
621 | void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; } |
622 | |
623 | /// Specify the maximum number of template instantiation |
624 | /// notes to emit along with a given diagnostic. |
625 | void setTemplateBacktraceLimit(unsigned Limit) { |
626 | TemplateBacktraceLimit = Limit; |
627 | } |
628 | |
629 | /// Retrieve the maximum number of template instantiation |
630 | /// notes to emit along with a given diagnostic. |
631 | unsigned getTemplateBacktraceLimit() const { |
632 | return TemplateBacktraceLimit; |
633 | } |
634 | |
635 | /// Specify the maximum number of constexpr evaluation |
636 | /// notes to emit along with a given diagnostic. |
637 | void setConstexprBacktraceLimit(unsigned Limit) { |
638 | ConstexprBacktraceLimit = Limit; |
639 | } |
640 | |
641 | /// Retrieve the maximum number of constexpr evaluation |
642 | /// notes to emit along with a given diagnostic. |
643 | unsigned getConstexprBacktraceLimit() const { |
644 | return ConstexprBacktraceLimit; |
645 | } |
646 | |
647 | /// When set to true, any unmapped warnings are ignored. |
648 | /// |
649 | /// If this and WarningsAsErrors are both set, then this one wins. |
650 | void setIgnoreAllWarnings(bool Val) { |
651 | GetCurDiagState()->IgnoreAllWarnings = Val; |
652 | } |
653 | bool getIgnoreAllWarnings() const { |
654 | return GetCurDiagState()->IgnoreAllWarnings; |
655 | } |
656 | |
657 | /// When set to true, any unmapped ignored warnings are no longer |
658 | /// ignored. |
659 | /// |
660 | /// If this and IgnoreAllWarnings are both set, then that one wins. |
661 | void setEnableAllWarnings(bool Val) { |
662 | GetCurDiagState()->EnableAllWarnings = Val; |
663 | } |
664 | bool getEnableAllWarnings() const { |
665 | return GetCurDiagState()->EnableAllWarnings; |
666 | } |
667 | |
668 | /// When set to true, any warnings reported are issued as errors. |
669 | void setWarningsAsErrors(bool Val) { |
670 | GetCurDiagState()->WarningsAsErrors = Val; |
671 | } |
672 | bool getWarningsAsErrors() const { |
673 | return GetCurDiagState()->WarningsAsErrors; |
674 | } |
675 | |
676 | /// When set to true, any error reported is made a fatal error. |
677 | void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; } |
678 | bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; } |
679 | |
680 | /// \brief When set to true, any fatal error reported is made an error. |
681 | /// |
682 | /// This setting takes precedence over the setErrorsAsFatal setting above. |
683 | void setFatalsAsError(bool Val) { FatalsAsError = Val; } |
684 | bool getFatalsAsError() const { return FatalsAsError; } |
685 | |
686 | /// When set to true mask warnings that come from system headers. |
687 | void setSuppressSystemWarnings(bool Val) { |
688 | GetCurDiagState()->SuppressSystemWarnings = Val; |
689 | } |
690 | bool getSuppressSystemWarnings() const { |
691 | return GetCurDiagState()->SuppressSystemWarnings; |
692 | } |
693 | |
694 | /// Suppress all diagnostics, to silence the front end when we |
695 | /// know that we don't want any more diagnostics to be passed along to the |
696 | /// client |
697 | void setSuppressAllDiagnostics(bool Val) { SuppressAllDiagnostics = Val; } |
698 | bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } |
699 | |
700 | /// Set type eliding, to skip outputting same types occurring in |
701 | /// template types. |
702 | void setElideType(bool Val) { ElideType = Val; } |
703 | bool getElideType() { return ElideType; } |
704 | |
705 | /// Set tree printing, to outputting the template difference in a |
706 | /// tree format. |
707 | void setPrintTemplateTree(bool Val) { PrintTemplateTree = Val; } |
708 | bool getPrintTemplateTree() { return PrintTemplateTree; } |
709 | |
710 | /// Set color printing, so the type diffing will inject color markers |
711 | /// into the output. |
712 | void setShowColors(bool Val) { ShowColors = Val; } |
713 | bool getShowColors() { return ShowColors; } |
714 | |
715 | /// Specify which overload candidates to show when overload resolution |
716 | /// fails. |
717 | /// |
718 | /// By default, we show all candidates. |
719 | void setShowOverloads(OverloadsShown Val) { |
720 | ShowOverloads = Val; |
721 | } |
722 | OverloadsShown getShowOverloads() const { return ShowOverloads; } |
723 | |
724 | /// When a call or operator fails, print out up to this many candidate |
725 | /// overloads as suggestions. |
726 | /// |
727 | /// With Ovl_Best, we set a high limit for the first nontrivial overload set |
728 | /// we print, and a lower limit for later sets. This way the user has a |
729 | /// chance of diagnosing at least one callsite in their program without |
730 | /// having to recompile with -fshow-overloads=all. |
731 | unsigned getNumOverloadCandidatesToShow() const { |
732 | switch (getShowOverloads()) { |
733 | case Ovl_All: |
734 | // INT_MAX rather than UINT_MAX so that we don't have to think about the |
735 | // effect of implicit conversions on this value. In practice we'll never |
736 | // hit 2^31 candidates anyway. |
737 | return std::numeric_limits<int>::max(); |
738 | case Ovl_Best: |
739 | return NumOverloadsToShow; |
740 | } |
741 | llvm_unreachable("invalid OverloadsShown kind" ); |
742 | } |
743 | |
744 | /// Call this after showing N overload candidates. This influences the value |
745 | /// returned by later calls to getNumOverloadCandidatesToShow(). |
746 | void overloadCandidatesShown(unsigned N) { |
747 | // Current heuristic: Start out with a large value for NumOverloadsToShow, |
748 | // and then once we print one nontrivially-large overload set, decrease it |
749 | // for future calls. |
750 | if (N > 4) { |
751 | NumOverloadsToShow = 4; |
752 | } |
753 | } |
754 | |
755 | /// Pretend that the last diagnostic issued was ignored, so any |
756 | /// subsequent notes will be suppressed, or restore a prior ignoring |
757 | /// state after ignoring some diagnostics and their notes, possibly in |
758 | /// the middle of another diagnostic. |
759 | /// |
760 | /// This can be used by clients who suppress diagnostics themselves. |
761 | void setLastDiagnosticIgnored(bool Ignored) { |
762 | if (LastDiagLevel == DiagnosticIDs::Fatal) |
763 | FatalErrorOccurred = true; |
764 | LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning; |
765 | } |
766 | |
767 | /// Determine whether the previous diagnostic was ignored. This can |
768 | /// be used by clients that want to determine whether notes attached to a |
769 | /// diagnostic will be suppressed. |
770 | bool isLastDiagnosticIgnored() const { |
771 | return LastDiagLevel == DiagnosticIDs::Ignored; |
772 | } |
773 | |
774 | /// Controls whether otherwise-unmapped extension diagnostics are |
775 | /// mapped onto ignore/warning/error. |
776 | /// |
777 | /// This corresponds to the GCC -pedantic and -pedantic-errors option. |
778 | void setExtensionHandlingBehavior(diag::Severity H) { |
779 | GetCurDiagState()->ExtBehavior = H; |
780 | } |
781 | diag::Severity getExtensionHandlingBehavior() const { |
782 | return GetCurDiagState()->ExtBehavior; |
783 | } |
784 | |
785 | /// Counter bumped when an __extension__ block is/ encountered. |
786 | /// |
787 | /// When non-zero, all extension diagnostics are entirely silenced, no |
788 | /// matter how they are mapped. |
789 | void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } |
790 | void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } |
791 | bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } |
792 | |
793 | /// This allows the client to specify that certain warnings are |
794 | /// ignored. |
795 | /// |
796 | /// Notes can never be mapped, errors can only be mapped to fatal, and |
797 | /// WARNINGs and EXTENSIONs can be mapped arbitrarily. |
798 | /// |
799 | /// \param Loc The source location that this change of diagnostic state should |
800 | /// take affect. It can be null if we are setting the latest state. |
801 | void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc); |
802 | |
803 | /// Change an entire diagnostic group (e.g. "unknown-pragmas") to |
804 | /// have the specified mapping. |
805 | /// |
806 | /// \returns true (and ignores the request) if "Group" was unknown, false |
807 | /// otherwise. |
808 | /// |
809 | /// \param Flavor The flavor of group to affect. -Rfoo does not affect the |
810 | /// state of the -Wfoo group and vice versa. |
811 | /// |
812 | /// \param Loc The source location that this change of diagnostic state should |
813 | /// take affect. It can be null if we are setting the state from command-line. |
814 | bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, |
815 | diag::Severity Map, |
816 | SourceLocation Loc = SourceLocation()); |
817 | bool setSeverityForGroup(diag::Flavor Flavor, diag::Group Group, |
818 | diag::Severity Map, |
819 | SourceLocation Loc = SourceLocation()); |
820 | |
821 | /// Set the warning-as-error flag for the given diagnostic group. |
822 | /// |
823 | /// This function always only operates on the current diagnostic state. |
824 | /// |
825 | /// \returns True if the given group is unknown, false otherwise. |
826 | bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled); |
827 | |
828 | /// Set the error-as-fatal flag for the given diagnostic group. |
829 | /// |
830 | /// This function always only operates on the current diagnostic state. |
831 | /// |
832 | /// \returns True if the given group is unknown, false otherwise. |
833 | bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled); |
834 | |
835 | /// Add the specified mapping to all diagnostics of the specified |
836 | /// flavor. |
837 | /// |
838 | /// Mainly to be used by -Wno-everything to disable all warnings but allow |
839 | /// subsequent -W options to enable specific warnings. |
840 | void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, |
841 | SourceLocation Loc = SourceLocation()); |
842 | |
843 | bool hasErrorOccurred() const { return ErrorOccurred; } |
844 | |
845 | /// Errors that actually prevent compilation, not those that are |
846 | /// upgraded from a warning by -Werror. |
847 | bool hasUncompilableErrorOccurred() const { |
848 | return UncompilableErrorOccurred; |
849 | } |
850 | bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } |
851 | |
852 | /// Determine whether any kind of unrecoverable error has occurred. |
853 | bool hasUnrecoverableErrorOccurred() const { |
854 | return FatalErrorOccurred || UnrecoverableErrorOccurred; |
855 | } |
856 | |
857 | unsigned getNumErrors() const { return NumErrors; } |
858 | unsigned getNumWarnings() const { return NumWarnings; } |
859 | |
860 | void setNumWarnings(unsigned NumWarnings) { |
861 | this->NumWarnings = NumWarnings; |
862 | } |
863 | |
864 | /// Return an ID for a diagnostic with the specified format string and |
865 | /// level. |
866 | /// |
867 | /// If this is the first request for this diagnostic, it is registered and |
868 | /// created, otherwise the existing ID is returned. |
869 | /// |
870 | /// \param FormatString A fixed diagnostic format string that will be hashed |
871 | /// and mapped to a unique DiagID. |
872 | template <unsigned N> |
873 | unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) { |
874 | return Diags->getCustomDiagID(L: (DiagnosticIDs::Level)L, |
875 | FormatString: StringRef(FormatString, N - 1)); |
876 | } |
877 | |
878 | /// Converts a diagnostic argument (as an intptr_t) into the string |
879 | /// that represents it. |
880 | void ConvertArgToString(ArgumentKind Kind, intptr_t Val, |
881 | StringRef Modifier, StringRef Argument, |
882 | ArrayRef<ArgumentValue> PrevArgs, |
883 | SmallVectorImpl<char> &Output, |
884 | ArrayRef<intptr_t> QualTypeVals) const { |
885 | ArgToStringFn(Kind, Val, Modifier, Argument, PrevArgs, Output, |
886 | ArgToStringCookie, QualTypeVals); |
887 | } |
888 | |
889 | void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { |
890 | ArgToStringFn = Fn; |
891 | ArgToStringCookie = Cookie; |
892 | } |
893 | |
894 | /// Note that the prior diagnostic was emitted by some other |
895 | /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic. |
896 | void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) { |
897 | LastDiagLevel = Other.LastDiagLevel; |
898 | } |
899 | |
900 | /// Reset the state of the diagnostic object to its initial configuration. |
901 | /// \param[in] soft - if true, doesn't reset the diagnostic mappings and state |
902 | void Reset(bool soft = false); |
903 | |
904 | //===--------------------------------------------------------------------===// |
905 | // DiagnosticsEngine classification and reporting interfaces. |
906 | // |
907 | |
908 | /// Determine whether the diagnostic is known to be ignored. |
909 | /// |
910 | /// This can be used to opportunistically avoid expensive checks when it's |
911 | /// known for certain that the diagnostic has been suppressed at the |
912 | /// specified location \p Loc. |
913 | /// |
914 | /// \param Loc The source location we are interested in finding out the |
915 | /// diagnostic state. Can be null in order to query the latest state. |
916 | bool isIgnored(unsigned DiagID, SourceLocation Loc) const { |
917 | return Diags->getDiagnosticSeverity(DiagID, Loc, Diag: *this) == |
918 | diag::Severity::Ignored; |
919 | } |
920 | |
921 | /// Based on the way the client configured the DiagnosticsEngine |
922 | /// object, classify the specified diagnostic ID into a Level, consumable by |
923 | /// the DiagnosticConsumer. |
924 | /// |
925 | /// To preserve invariant assumptions, this function should not be used to |
926 | /// influence parse or semantic analysis actions. Instead consider using |
927 | /// \c isIgnored(). |
928 | /// |
929 | /// \param Loc The source location we are interested in finding out the |
930 | /// diagnostic state. Can be null in order to query the latest state. |
931 | Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { |
932 | return (Level)Diags->getDiagnosticLevel(DiagID, Loc, Diag: *this); |
933 | } |
934 | |
935 | /// Issue the message to the client. |
936 | /// |
937 | /// This actually returns an instance of DiagnosticBuilder which emits the |
938 | /// diagnostics (through @c ProcessDiag) when it is destroyed. |
939 | /// |
940 | /// \param DiagID A member of the @c diag::kind enum. |
941 | /// \param Loc Represents the source location associated with the diagnostic, |
942 | /// which can be an invalid location if no position information is available. |
943 | inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID); |
944 | inline DiagnosticBuilder Report(unsigned DiagID); |
945 | |
946 | void Report(const StoredDiagnostic &storedDiag); |
947 | |
948 | /// Determine whethere there is already a diagnostic in flight. |
949 | bool isDiagnosticInFlight() const { |
950 | return CurDiagID != std::numeric_limits<unsigned>::max(); |
951 | } |
952 | |
953 | /// Set the "delayed" diagnostic that will be emitted once |
954 | /// the current diagnostic completes. |
955 | /// |
956 | /// If a diagnostic is already in-flight but the front end must |
957 | /// report a problem (e.g., with an inconsistent file system |
958 | /// state), this routine sets a "delayed" diagnostic that will be |
959 | /// emitted after the current diagnostic completes. This should |
960 | /// only be used for fatal errors detected at inconvenient |
961 | /// times. If emitting a delayed diagnostic causes a second delayed |
962 | /// diagnostic to be introduced, that second delayed diagnostic |
963 | /// will be ignored. |
964 | /// |
965 | /// \param DiagID The ID of the diagnostic being delayed. |
966 | /// |
967 | /// \param Arg1 A string argument that will be provided to the |
968 | /// diagnostic. A copy of this string will be stored in the |
969 | /// DiagnosticsEngine object itself. |
970 | /// |
971 | /// \param Arg2 A string argument that will be provided to the |
972 | /// diagnostic. A copy of this string will be stored in the |
973 | /// DiagnosticsEngine object itself. |
974 | /// |
975 | /// \param Arg3 A string argument that will be provided to the |
976 | /// diagnostic. A copy of this string will be stored in the |
977 | /// DiagnosticsEngine object itself. |
978 | void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "" , |
979 | StringRef Arg2 = "" , StringRef Arg3 = "" ); |
980 | |
981 | /// Clear out the current diagnostic. |
982 | void Clear() { CurDiagID = std::numeric_limits<unsigned>::max(); } |
983 | |
984 | /// Return the value associated with this diagnostic flag. |
985 | StringRef getFlagValue() const { return FlagValue; } |
986 | |
987 | private: |
988 | // This is private state used by DiagnosticBuilder. We put it here instead of |
989 | // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight |
990 | // object. This implementation choice means that we can only have one |
991 | // diagnostic "in flight" at a time, but this seems to be a reasonable |
992 | // tradeoff to keep these objects small. Assertions verify that only one |
993 | // diagnostic is in flight at a time. |
994 | friend class Diagnostic; |
995 | friend class DiagnosticBuilder; |
996 | friend class DiagnosticErrorTrap; |
997 | friend class DiagnosticIDs; |
998 | friend class PartialDiagnostic; |
999 | |
1000 | /// Report the delayed diagnostic. |
1001 | void ReportDelayed(); |
1002 | |
1003 | /// The location of the current diagnostic that is in flight. |
1004 | SourceLocation CurDiagLoc; |
1005 | |
1006 | /// The ID of the current diagnostic that is in flight. |
1007 | /// |
1008 | /// This is set to std::numeric_limits<unsigned>::max() when there is no |
1009 | /// diagnostic in flight. |
1010 | unsigned CurDiagID; |
1011 | |
1012 | enum { |
1013 | /// The maximum number of arguments we can hold. |
1014 | /// |
1015 | /// We currently only support up to 10 arguments (%0-%9). A single |
1016 | /// diagnostic with more than that almost certainly has to be simplified |
1017 | /// anyway. |
1018 | MaxArguments = DiagnosticStorage::MaxArguments, |
1019 | }; |
1020 | |
1021 | DiagnosticStorage DiagStorage; |
1022 | |
1023 | DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) { |
1024 | bool isPragma = L.isValid(); |
1025 | DiagnosticMapping Mapping = |
1026 | DiagnosticMapping::Make(Severity: Map, /*IsUser=*/IsUser: true, IsPragma: isPragma); |
1027 | |
1028 | // If this is a pragma mapping, then set the diagnostic mapping flags so |
1029 | // that we override command line options. |
1030 | if (isPragma) { |
1031 | Mapping.setNoWarningAsError(true); |
1032 | Mapping.setNoErrorAsFatal(true); |
1033 | } |
1034 | |
1035 | return Mapping; |
1036 | } |
1037 | |
1038 | /// Used to report a diagnostic that is finally fully formed. |
1039 | /// |
1040 | /// \returns true if the diagnostic was emitted, false if it was suppressed. |
1041 | bool ProcessDiag() { |
1042 | return Diags->ProcessDiag(Diag&: *this); |
1043 | } |
1044 | |
1045 | /// @name Diagnostic Emission |
1046 | /// @{ |
1047 | protected: |
1048 | friend class ASTReader; |
1049 | friend class ASTWriter; |
1050 | |
1051 | // Sema requires access to the following functions because the current design |
1052 | // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to |
1053 | // access us directly to ensure we minimize the emitted code for the common |
1054 | // Sema::Diag() patterns. |
1055 | friend class Sema; |
1056 | |
1057 | /// Emit the current diagnostic and clear the diagnostic state. |
1058 | /// |
1059 | /// \param Force Emit the diagnostic regardless of suppression settings. |
1060 | bool EmitCurrentDiagnostic(bool Force = false); |
1061 | |
1062 | unsigned getCurrentDiagID() const { return CurDiagID; } |
1063 | |
1064 | SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; } |
1065 | |
1066 | /// @} |
1067 | }; |
1068 | |
1069 | /// RAII class that determines when any errors have occurred |
1070 | /// between the time the instance was created and the time it was |
1071 | /// queried. |
1072 | /// |
1073 | /// Note that you almost certainly do not want to use this. It's usually |
1074 | /// meaningless to ask whether a particular scope triggered an error message, |
1075 | /// because error messages outside that scope can mark things invalid (or cause |
1076 | /// us to reach an error limit), which can suppress errors within that scope. |
1077 | class DiagnosticErrorTrap { |
1078 | DiagnosticsEngine &Diag; |
1079 | unsigned NumErrors; |
1080 | unsigned NumUnrecoverableErrors; |
1081 | |
1082 | public: |
1083 | explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag) |
1084 | : Diag(Diag) { reset(); } |
1085 | |
1086 | /// Determine whether any errors have occurred since this |
1087 | /// object instance was created. |
1088 | bool hasErrorOccurred() const { |
1089 | return Diag.TrapNumErrorsOccurred > NumErrors; |
1090 | } |
1091 | |
1092 | /// Determine whether any unrecoverable errors have occurred since this |
1093 | /// object instance was created. |
1094 | bool hasUnrecoverableErrorOccurred() const { |
1095 | return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors; |
1096 | } |
1097 | |
1098 | /// Set to initial state of "no errors occurred". |
1099 | void reset() { |
1100 | NumErrors = Diag.TrapNumErrorsOccurred; |
1101 | NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred; |
1102 | } |
1103 | }; |
1104 | |
1105 | /// The streaming interface shared between DiagnosticBuilder and |
1106 | /// PartialDiagnostic. This class is not intended to be constructed directly |
1107 | /// but only as base class of DiagnosticBuilder and PartialDiagnostic builder. |
1108 | /// |
1109 | /// Any new type of argument accepted by DiagnosticBuilder and PartialDiagnostic |
1110 | /// should be implemented as a '<<' operator of StreamingDiagnostic, e.g. |
1111 | /// |
1112 | /// const StreamingDiagnostic& |
1113 | /// operator<<(const StreamingDiagnostic&, NewArgType); |
1114 | /// |
1115 | class StreamingDiagnostic { |
1116 | public: |
1117 | /// An allocator for DiagnosticStorage objects, which uses a small cache to |
1118 | /// objects, used to reduce malloc()/free() traffic for partial diagnostics. |
1119 | class DiagStorageAllocator { |
1120 | static const unsigned NumCached = 16; |
1121 | DiagnosticStorage Cached[NumCached]; |
1122 | DiagnosticStorage *FreeList[NumCached]; |
1123 | unsigned NumFreeListEntries; |
1124 | |
1125 | public: |
1126 | DiagStorageAllocator(); |
1127 | ~DiagStorageAllocator(); |
1128 | |
1129 | /// Allocate new storage. |
1130 | DiagnosticStorage *Allocate() { |
1131 | if (NumFreeListEntries == 0) |
1132 | return new DiagnosticStorage; |
1133 | |
1134 | DiagnosticStorage *Result = FreeList[--NumFreeListEntries]; |
1135 | Result->NumDiagArgs = 0; |
1136 | Result->DiagRanges.clear(); |
1137 | Result->FixItHints.clear(); |
1138 | return Result; |
1139 | } |
1140 | |
1141 | /// Free the given storage object. |
1142 | void Deallocate(DiagnosticStorage *S) { |
1143 | if (S >= Cached && S <= Cached + NumCached) { |
1144 | FreeList[NumFreeListEntries++] = S; |
1145 | return; |
1146 | } |
1147 | |
1148 | delete S; |
1149 | } |
1150 | }; |
1151 | |
1152 | protected: |
1153 | mutable DiagnosticStorage *DiagStorage = nullptr; |
1154 | |
1155 | /// Allocator used to allocate storage for this diagnostic. |
1156 | DiagStorageAllocator *Allocator = nullptr; |
1157 | |
1158 | public: |
1159 | /// Retrieve storage for this particular diagnostic. |
1160 | DiagnosticStorage *getStorage() const { |
1161 | if (DiagStorage) |
1162 | return DiagStorage; |
1163 | |
1164 | assert(Allocator); |
1165 | DiagStorage = Allocator->Allocate(); |
1166 | return DiagStorage; |
1167 | } |
1168 | |
1169 | void freeStorage() { |
1170 | if (!DiagStorage) |
1171 | return; |
1172 | |
1173 | // The hot path for PartialDiagnostic is when we just used it to wrap an ID |
1174 | // (typically so we have the flexibility of passing a more complex |
1175 | // diagnostic into the callee, but that does not commonly occur). |
1176 | // |
1177 | // Split this out into a slow function for silly compilers (*cough*) which |
1178 | // can't do decent partial inlining. |
1179 | freeStorageSlow(); |
1180 | } |
1181 | |
1182 | void freeStorageSlow() { |
1183 | if (!Allocator) |
1184 | return; |
1185 | Allocator->Deallocate(S: DiagStorage); |
1186 | DiagStorage = nullptr; |
1187 | } |
1188 | |
1189 | void AddTaggedVal(uint64_t V, DiagnosticsEngine::ArgumentKind Kind) const { |
1190 | if (!DiagStorage) |
1191 | DiagStorage = getStorage(); |
1192 | |
1193 | assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && |
1194 | "Too many arguments to diagnostic!" ); |
1195 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; |
1196 | DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; |
1197 | } |
1198 | |
1199 | void AddString(StringRef V) const { |
1200 | if (!DiagStorage) |
1201 | DiagStorage = getStorage(); |
1202 | |
1203 | assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && |
1204 | "Too many arguments to diagnostic!" ); |
1205 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = |
1206 | DiagnosticsEngine::ak_std_string; |
1207 | DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = std::string(V); |
1208 | } |
1209 | |
1210 | void AddSourceRange(const CharSourceRange &R) const { |
1211 | if (!DiagStorage) |
1212 | DiagStorage = getStorage(); |
1213 | |
1214 | DiagStorage->DiagRanges.push_back(Elt: R); |
1215 | } |
1216 | |
1217 | void AddFixItHint(const FixItHint &Hint) const { |
1218 | if (Hint.isNull()) |
1219 | return; |
1220 | |
1221 | if (!DiagStorage) |
1222 | DiagStorage = getStorage(); |
1223 | |
1224 | DiagStorage->FixItHints.push_back(Elt: Hint); |
1225 | } |
1226 | |
1227 | /// Conversion of StreamingDiagnostic to bool always returns \c true. |
1228 | /// |
1229 | /// This allows is to be used in boolean error contexts (where \c true is |
1230 | /// used to indicate that an error has occurred), like: |
1231 | /// \code |
1232 | /// return Diag(...); |
1233 | /// \endcode |
1234 | operator bool() const { return true; } |
1235 | |
1236 | protected: |
1237 | StreamingDiagnostic() = default; |
1238 | |
1239 | /// Construct with an external storage not owned by itself. The allocator |
1240 | /// is a null pointer in this case. |
1241 | explicit StreamingDiagnostic(DiagnosticStorage *Storage) |
1242 | : DiagStorage(Storage) {} |
1243 | |
1244 | /// Construct with a storage allocator which will manage the storage. The |
1245 | /// allocator is not a null pointer in this case. |
1246 | explicit StreamingDiagnostic(DiagStorageAllocator &Alloc) |
1247 | : Allocator(&Alloc) {} |
1248 | |
1249 | StreamingDiagnostic(const StreamingDiagnostic &Diag) = default; |
1250 | StreamingDiagnostic(StreamingDiagnostic &&Diag) = default; |
1251 | |
1252 | ~StreamingDiagnostic() { freeStorage(); } |
1253 | }; |
1254 | |
1255 | //===----------------------------------------------------------------------===// |
1256 | // DiagnosticBuilder |
1257 | //===----------------------------------------------------------------------===// |
1258 | |
1259 | /// A little helper class used to produce diagnostics. |
1260 | /// |
1261 | /// This is constructed by the DiagnosticsEngine::Report method, and |
1262 | /// allows insertion of extra information (arguments and source ranges) into |
1263 | /// the currently "in flight" diagnostic. When the temporary for the builder |
1264 | /// is destroyed, the diagnostic is issued. |
1265 | /// |
1266 | /// Note that many of these will be created as temporary objects (many call |
1267 | /// sites), so we want them to be small and we never want their address taken. |
1268 | /// This ensures that compilers with somewhat reasonable optimizers will promote |
1269 | /// the common fields to registers, eliminating increments of the NumArgs field, |
1270 | /// for example. |
1271 | class DiagnosticBuilder : public StreamingDiagnostic { |
1272 | friend class DiagnosticsEngine; |
1273 | friend class PartialDiagnostic; |
1274 | |
1275 | mutable DiagnosticsEngine *DiagObj = nullptr; |
1276 | |
1277 | /// Status variable indicating if this diagnostic is still active. |
1278 | /// |
1279 | // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)), |
1280 | // but LLVM is not currently smart enough to eliminate the null check that |
1281 | // Emit() would end up with if we used that as our status variable. |
1282 | mutable bool IsActive = false; |
1283 | |
1284 | /// Flag indicating that this diagnostic is being emitted via a |
1285 | /// call to ForceEmit. |
1286 | mutable bool IsForceEmit = false; |
1287 | |
1288 | DiagnosticBuilder() = default; |
1289 | |
1290 | explicit DiagnosticBuilder(DiagnosticsEngine *diagObj) |
1291 | : StreamingDiagnostic(&diagObj->DiagStorage), DiagObj(diagObj), |
1292 | IsActive(true) { |
1293 | assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!" ); |
1294 | assert(DiagStorage && |
1295 | "DiagnosticBuilder requires a valid DiagnosticStorage!" ); |
1296 | DiagStorage->NumDiagArgs = 0; |
1297 | DiagStorage->DiagRanges.clear(); |
1298 | DiagStorage->FixItHints.clear(); |
1299 | } |
1300 | |
1301 | protected: |
1302 | /// Clear out the current diagnostic. |
1303 | void Clear() const { |
1304 | DiagObj = nullptr; |
1305 | IsActive = false; |
1306 | IsForceEmit = false; |
1307 | } |
1308 | |
1309 | /// Determine whether this diagnostic is still active. |
1310 | bool isActive() const { return IsActive; } |
1311 | |
1312 | /// Force the diagnostic builder to emit the diagnostic now. |
1313 | /// |
1314 | /// Once this function has been called, the DiagnosticBuilder object |
1315 | /// should not be used again before it is destroyed. |
1316 | /// |
1317 | /// \returns true if a diagnostic was emitted, false if the |
1318 | /// diagnostic was suppressed. |
1319 | bool Emit() { |
1320 | // If this diagnostic is inactive, then its soul was stolen by the copy ctor |
1321 | // (or by a subclass, as in SemaDiagnosticBuilder). |
1322 | if (!isActive()) return false; |
1323 | |
1324 | // Process the diagnostic. |
1325 | bool Result = DiagObj->EmitCurrentDiagnostic(Force: IsForceEmit); |
1326 | |
1327 | // This diagnostic is dead. |
1328 | Clear(); |
1329 | |
1330 | return Result; |
1331 | } |
1332 | |
1333 | public: |
1334 | /// Copy constructor. When copied, this "takes" the diagnostic info from the |
1335 | /// input and neuters it. |
1336 | DiagnosticBuilder(const DiagnosticBuilder &D) : StreamingDiagnostic() { |
1337 | DiagObj = D.DiagObj; |
1338 | DiagStorage = D.DiagStorage; |
1339 | IsActive = D.IsActive; |
1340 | IsForceEmit = D.IsForceEmit; |
1341 | D.Clear(); |
1342 | } |
1343 | |
1344 | template <typename T> const DiagnosticBuilder &operator<<(const T &V) const { |
1345 | assert(isActive() && "Clients must not add to cleared diagnostic!" ); |
1346 | const StreamingDiagnostic &DB = *this; |
1347 | DB << V; |
1348 | return *this; |
1349 | } |
1350 | |
1351 | // It is necessary to limit this to rvalue reference to avoid calling this |
1352 | // function with a bitfield lvalue argument since non-const reference to |
1353 | // bitfield is not allowed. |
1354 | template <typename T, |
1355 | typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> |
1356 | const DiagnosticBuilder &operator<<(T &&V) const { |
1357 | assert(isActive() && "Clients must not add to cleared diagnostic!" ); |
1358 | const StreamingDiagnostic &DB = *this; |
1359 | DB << std::move(V); |
1360 | return *this; |
1361 | } |
1362 | |
1363 | DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete; |
1364 | |
1365 | /// Emits the diagnostic. |
1366 | ~DiagnosticBuilder() { Emit(); } |
1367 | |
1368 | /// Forces the diagnostic to be emitted. |
1369 | const DiagnosticBuilder &setForceEmit() const { |
1370 | IsForceEmit = true; |
1371 | return *this; |
1372 | } |
1373 | |
1374 | void addFlagValue(StringRef V) const { DiagObj->FlagValue = std::string(V); } |
1375 | }; |
1376 | |
1377 | struct AddFlagValue { |
1378 | StringRef Val; |
1379 | |
1380 | explicit AddFlagValue(StringRef V) : Val(V) {} |
1381 | }; |
1382 | |
1383 | /// Register a value for the flag in the current diagnostic. This |
1384 | /// value will be shown as the suffix "=value" after the flag name. It is |
1385 | /// useful in cases where the diagnostic flag accepts values (e.g., |
1386 | /// -Rpass or -Wframe-larger-than). |
1387 | inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, |
1388 | const AddFlagValue V) { |
1389 | DB.addFlagValue(V: V.Val); |
1390 | return DB; |
1391 | } |
1392 | |
1393 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1394 | StringRef S) { |
1395 | DB.AddString(V: S); |
1396 | return DB; |
1397 | } |
1398 | |
1399 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1400 | const char *Str) { |
1401 | DB.AddTaggedVal(V: reinterpret_cast<intptr_t>(Str), |
1402 | Kind: DiagnosticsEngine::ak_c_string); |
1403 | return DB; |
1404 | } |
1405 | |
1406 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1407 | int I) { |
1408 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_sint); |
1409 | return DB; |
1410 | } |
1411 | |
1412 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1413 | long I) { |
1414 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_sint); |
1415 | return DB; |
1416 | } |
1417 | |
1418 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1419 | long long I) { |
1420 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_sint); |
1421 | return DB; |
1422 | } |
1423 | |
1424 | // We use enable_if here to prevent that this overload is selected for |
1425 | // pointers or other arguments that are implicitly convertible to bool. |
1426 | template <typename T> |
1427 | inline std::enable_if_t<std::is_same<T, bool>::value, |
1428 | const StreamingDiagnostic &> |
1429 | operator<<(const StreamingDiagnostic &DB, T I) { |
1430 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_sint); |
1431 | return DB; |
1432 | } |
1433 | |
1434 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1435 | unsigned I) { |
1436 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_uint); |
1437 | return DB; |
1438 | } |
1439 | |
1440 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1441 | unsigned long I) { |
1442 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_uint); |
1443 | return DB; |
1444 | } |
1445 | |
1446 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1447 | unsigned long long I) { |
1448 | DB.AddTaggedVal(V: I, Kind: DiagnosticsEngine::ak_uint); |
1449 | return DB; |
1450 | } |
1451 | |
1452 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1453 | tok::TokenKind I) { |
1454 | DB.AddTaggedVal(V: static_cast<unsigned>(I), Kind: DiagnosticsEngine::ak_tokenkind); |
1455 | return DB; |
1456 | } |
1457 | |
1458 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1459 | const IdentifierInfo *II) { |
1460 | DB.AddTaggedVal(V: reinterpret_cast<intptr_t>(II), |
1461 | Kind: DiagnosticsEngine::ak_identifierinfo); |
1462 | return DB; |
1463 | } |
1464 | |
1465 | // Adds a DeclContext to the diagnostic. The enable_if template magic is here |
1466 | // so that we only match those arguments that are (statically) DeclContexts; |
1467 | // other arguments that derive from DeclContext (e.g., RecordDecls) will not |
1468 | // match. |
1469 | template <typename T> |
1470 | inline std::enable_if_t< |
1471 | std::is_same<std::remove_const_t<T>, DeclContext>::value, |
1472 | const StreamingDiagnostic &> |
1473 | operator<<(const StreamingDiagnostic &DB, T *DC) { |
1474 | DB.AddTaggedVal(V: reinterpret_cast<intptr_t>(DC), |
1475 | Kind: DiagnosticsEngine::ak_declcontext); |
1476 | return DB; |
1477 | } |
1478 | |
1479 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1480 | SourceLocation L) { |
1481 | DB.AddSourceRange(R: CharSourceRange::getTokenRange(R: L)); |
1482 | return DB; |
1483 | } |
1484 | |
1485 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1486 | SourceRange R) { |
1487 | DB.AddSourceRange(R: CharSourceRange::getTokenRange(R)); |
1488 | return DB; |
1489 | } |
1490 | |
1491 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1492 | ArrayRef<SourceRange> Ranges) { |
1493 | for (SourceRange R : Ranges) |
1494 | DB.AddSourceRange(R: CharSourceRange::getTokenRange(R)); |
1495 | return DB; |
1496 | } |
1497 | |
1498 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1499 | const CharSourceRange &R) { |
1500 | DB.AddSourceRange(R); |
1501 | return DB; |
1502 | } |
1503 | |
1504 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1505 | const FixItHint &Hint) { |
1506 | DB.AddFixItHint(Hint); |
1507 | return DB; |
1508 | } |
1509 | |
1510 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1511 | ArrayRef<FixItHint> Hints) { |
1512 | for (const FixItHint &Hint : Hints) |
1513 | DB.AddFixItHint(Hint); |
1514 | return DB; |
1515 | } |
1516 | |
1517 | inline const StreamingDiagnostic & |
1518 | operator<<(const StreamingDiagnostic &DB, |
1519 | const std::optional<SourceRange> &Opt) { |
1520 | if (Opt) |
1521 | DB << *Opt; |
1522 | return DB; |
1523 | } |
1524 | |
1525 | inline const StreamingDiagnostic & |
1526 | operator<<(const StreamingDiagnostic &DB, |
1527 | const std::optional<CharSourceRange> &Opt) { |
1528 | if (Opt) |
1529 | DB << *Opt; |
1530 | return DB; |
1531 | } |
1532 | |
1533 | inline const StreamingDiagnostic & |
1534 | operator<<(const StreamingDiagnostic &DB, const std::optional<FixItHint> &Opt) { |
1535 | if (Opt) |
1536 | DB << *Opt; |
1537 | return DB; |
1538 | } |
1539 | |
1540 | /// A nullability kind paired with a bit indicating whether it used a |
1541 | /// context-sensitive keyword. |
1542 | using DiagNullabilityKind = std::pair<NullabilityKind, bool>; |
1543 | |
1544 | const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1545 | DiagNullabilityKind nullability); |
1546 | |
1547 | inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, |
1548 | unsigned DiagID) { |
1549 | assert(CurDiagID == std::numeric_limits<unsigned>::max() && |
1550 | "Multiple diagnostics in flight at once!" ); |
1551 | CurDiagLoc = Loc; |
1552 | CurDiagID = DiagID; |
1553 | FlagValue.clear(); |
1554 | return DiagnosticBuilder(this); |
1555 | } |
1556 | |
1557 | const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, |
1558 | llvm::Error &&E); |
1559 | |
1560 | inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) { |
1561 | return Report(Loc: SourceLocation(), DiagID); |
1562 | } |
1563 | |
1564 | //===----------------------------------------------------------------------===// |
1565 | // Diagnostic |
1566 | //===----------------------------------------------------------------------===// |
1567 | |
1568 | /// A little helper class (which is basically a smart pointer that forwards |
1569 | /// info from DiagnosticsEngine) that allows clients to enquire about the |
1570 | /// currently in-flight diagnostic. |
1571 | class Diagnostic { |
1572 | const DiagnosticsEngine *DiagObj; |
1573 | std::optional<StringRef> StoredDiagMessage; |
1574 | |
1575 | public: |
1576 | explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {} |
1577 | Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage) |
1578 | : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {} |
1579 | |
1580 | const DiagnosticsEngine *getDiags() const { return DiagObj; } |
1581 | unsigned getID() const { return DiagObj->CurDiagID; } |
1582 | const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; } |
1583 | bool hasSourceManager() const { return DiagObj->hasSourceManager(); } |
1584 | SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} |
1585 | |
1586 | unsigned getNumArgs() const { return DiagObj->DiagStorage.NumDiagArgs; } |
1587 | |
1588 | /// Return the kind of the specified index. |
1589 | /// |
1590 | /// Based on the kind of argument, the accessors below can be used to get |
1591 | /// the value. |
1592 | /// |
1593 | /// \pre Idx < getNumArgs() |
1594 | DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const { |
1595 | assert(Idx < getNumArgs() && "Argument index out of range!" ); |
1596 | return (DiagnosticsEngine::ArgumentKind) |
1597 | DiagObj->DiagStorage.DiagArgumentsKind[Idx]; |
1598 | } |
1599 | |
1600 | /// Return the provided argument string specified by \p Idx. |
1601 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string |
1602 | const std::string &getArgStdStr(unsigned Idx) const { |
1603 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string && |
1604 | "invalid argument accessor!" ); |
1605 | return DiagObj->DiagStorage.DiagArgumentsStr[Idx]; |
1606 | } |
1607 | |
1608 | /// Return the specified C string argument. |
1609 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string |
1610 | const char *getArgCStr(unsigned Idx) const { |
1611 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string && |
1612 | "invalid argument accessor!" ); |
1613 | return reinterpret_cast<const char *>( |
1614 | DiagObj->DiagStorage.DiagArgumentsVal[Idx]); |
1615 | } |
1616 | |
1617 | /// Return the specified signed integer argument. |
1618 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint |
1619 | int64_t getArgSInt(unsigned Idx) const { |
1620 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint && |
1621 | "invalid argument accessor!" ); |
1622 | return (int64_t)DiagObj->DiagStorage.DiagArgumentsVal[Idx]; |
1623 | } |
1624 | |
1625 | /// Return the specified unsigned integer argument. |
1626 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint |
1627 | uint64_t getArgUInt(unsigned Idx) const { |
1628 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint && |
1629 | "invalid argument accessor!" ); |
1630 | return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; |
1631 | } |
1632 | |
1633 | /// Return the specified IdentifierInfo argument. |
1634 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo |
1635 | const IdentifierInfo *getArgIdentifier(unsigned Idx) const { |
1636 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && |
1637 | "invalid argument accessor!" ); |
1638 | return reinterpret_cast<IdentifierInfo *>( |
1639 | DiagObj->DiagStorage.DiagArgumentsVal[Idx]); |
1640 | } |
1641 | |
1642 | /// Return the specified non-string argument in an opaque form. |
1643 | /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string |
1644 | uint64_t getRawArg(unsigned Idx) const { |
1645 | assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string && |
1646 | "invalid argument accessor!" ); |
1647 | return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; |
1648 | } |
1649 | |
1650 | /// Return the number of source ranges associated with this diagnostic. |
1651 | unsigned getNumRanges() const { |
1652 | return DiagObj->DiagStorage.DiagRanges.size(); |
1653 | } |
1654 | |
1655 | /// \pre Idx < getNumRanges() |
1656 | const CharSourceRange &getRange(unsigned Idx) const { |
1657 | assert(Idx < getNumRanges() && "Invalid diagnostic range index!" ); |
1658 | return DiagObj->DiagStorage.DiagRanges[Idx]; |
1659 | } |
1660 | |
1661 | /// Return an array reference for this diagnostic's ranges. |
1662 | ArrayRef<CharSourceRange> getRanges() const { |
1663 | return DiagObj->DiagStorage.DiagRanges; |
1664 | } |
1665 | |
1666 | unsigned getNumFixItHints() const { |
1667 | return DiagObj->DiagStorage.FixItHints.size(); |
1668 | } |
1669 | |
1670 | const FixItHint &getFixItHint(unsigned Idx) const { |
1671 | assert(Idx < getNumFixItHints() && "Invalid index!" ); |
1672 | return DiagObj->DiagStorage.FixItHints[Idx]; |
1673 | } |
1674 | |
1675 | ArrayRef<FixItHint> getFixItHints() const { |
1676 | return DiagObj->DiagStorage.FixItHints; |
1677 | } |
1678 | |
1679 | /// Format this diagnostic into a string, substituting the |
1680 | /// formal arguments into the %0 slots. |
1681 | /// |
1682 | /// The result is appended onto the \p OutStr array. |
1683 | void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const; |
1684 | |
1685 | /// Format the given format-string into the output buffer using the |
1686 | /// arguments stored in this diagnostic. |
1687 | void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, |
1688 | SmallVectorImpl<char> &OutStr) const; |
1689 | }; |
1690 | |
1691 | /** |
1692 | * Represents a diagnostic in a form that can be retained until its |
1693 | * corresponding source manager is destroyed. |
1694 | */ |
1695 | class StoredDiagnostic { |
1696 | unsigned ID; |
1697 | DiagnosticsEngine::Level Level; |
1698 | FullSourceLoc Loc; |
1699 | std::string Message; |
1700 | std::vector<CharSourceRange> Ranges; |
1701 | std::vector<FixItHint> FixIts; |
1702 | |
1703 | public: |
1704 | StoredDiagnostic() = default; |
1705 | StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); |
1706 | StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, |
1707 | StringRef Message); |
1708 | StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, |
1709 | StringRef Message, FullSourceLoc Loc, |
1710 | ArrayRef<CharSourceRange> Ranges, |
1711 | ArrayRef<FixItHint> Fixits); |
1712 | |
1713 | /// Evaluates true when this object stores a diagnostic. |
1714 | explicit operator bool() const { return !Message.empty(); } |
1715 | |
1716 | unsigned getID() const { return ID; } |
1717 | DiagnosticsEngine::Level getLevel() const { return Level; } |
1718 | const FullSourceLoc &getLocation() const { return Loc; } |
1719 | StringRef getMessage() const { return Message; } |
1720 | |
1721 | void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } |
1722 | |
1723 | using range_iterator = std::vector<CharSourceRange>::const_iterator; |
1724 | |
1725 | range_iterator range_begin() const { return Ranges.begin(); } |
1726 | range_iterator range_end() const { return Ranges.end(); } |
1727 | unsigned range_size() const { return Ranges.size(); } |
1728 | |
1729 | ArrayRef<CharSourceRange> getRanges() const { return llvm::ArrayRef(Ranges); } |
1730 | |
1731 | using fixit_iterator = std::vector<FixItHint>::const_iterator; |
1732 | |
1733 | fixit_iterator fixit_begin() const { return FixIts.begin(); } |
1734 | fixit_iterator fixit_end() const { return FixIts.end(); } |
1735 | unsigned fixit_size() const { return FixIts.size(); } |
1736 | |
1737 | ArrayRef<FixItHint> getFixIts() const { return llvm::ArrayRef(FixIts); } |
1738 | }; |
1739 | |
1740 | // Simple debug printing of StoredDiagnostic. |
1741 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StoredDiagnostic &); |
1742 | |
1743 | /// Abstract interface, implemented by clients of the front-end, which |
1744 | /// formats and prints fully processed diagnostics. |
1745 | class DiagnosticConsumer { |
1746 | protected: |
1747 | unsigned NumWarnings = 0; ///< Number of warnings reported |
1748 | unsigned NumErrors = 0; ///< Number of errors reported |
1749 | |
1750 | public: |
1751 | DiagnosticConsumer() = default; |
1752 | virtual ~DiagnosticConsumer(); |
1753 | |
1754 | unsigned getNumErrors() const { return NumErrors; } |
1755 | unsigned getNumWarnings() const { return NumWarnings; } |
1756 | virtual void clear() { NumWarnings = NumErrors = 0; } |
1757 | |
1758 | /// Callback to inform the diagnostic client that processing |
1759 | /// of a source file is beginning. |
1760 | /// |
1761 | /// Note that diagnostics may be emitted outside the processing of a source |
1762 | /// file, for example during the parsing of command line options. However, |
1763 | /// diagnostics with source range information are required to only be emitted |
1764 | /// in between BeginSourceFile() and EndSourceFile(). |
1765 | /// |
1766 | /// \param LangOpts The language options for the source file being processed. |
1767 | /// \param PP The preprocessor object being used for the source; this is |
1768 | /// optional, e.g., it may not be present when processing AST source files. |
1769 | virtual void BeginSourceFile(const LangOptions &LangOpts, |
1770 | const Preprocessor *PP = nullptr) {} |
1771 | |
1772 | /// Callback to inform the diagnostic client that processing |
1773 | /// of a source file has ended. |
1774 | /// |
1775 | /// The diagnostic client should assume that any objects made available via |
1776 | /// BeginSourceFile() are inaccessible. |
1777 | virtual void EndSourceFile() {} |
1778 | |
1779 | /// Callback to inform the diagnostic client that processing of all |
1780 | /// source files has ended. |
1781 | virtual void finish() {} |
1782 | |
1783 | /// Indicates whether the diagnostics handled by this |
1784 | /// DiagnosticConsumer should be included in the number of diagnostics |
1785 | /// reported by DiagnosticsEngine. |
1786 | /// |
1787 | /// The default implementation returns true. |
1788 | virtual bool IncludeInDiagnosticCounts() const; |
1789 | |
1790 | /// Handle this diagnostic, reporting it to the user or |
1791 | /// capturing it to a log as needed. |
1792 | /// |
1793 | /// The default implementation just keeps track of the total number of |
1794 | /// warnings and errors. |
1795 | virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, |
1796 | const Diagnostic &Info); |
1797 | }; |
1798 | |
1799 | /// A diagnostic client that ignores all diagnostics. |
1800 | class IgnoringDiagConsumer : public DiagnosticConsumer { |
1801 | virtual void anchor(); |
1802 | |
1803 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, |
1804 | const Diagnostic &Info) override { |
1805 | // Just ignore it. |
1806 | } |
1807 | }; |
1808 | |
1809 | /// Diagnostic consumer that forwards diagnostics along to an |
1810 | /// existing, already-initialized diagnostic consumer. |
1811 | /// |
1812 | class ForwardingDiagnosticConsumer : public DiagnosticConsumer { |
1813 | DiagnosticConsumer &Target; |
1814 | |
1815 | public: |
1816 | ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {} |
1817 | ~ForwardingDiagnosticConsumer() override; |
1818 | |
1819 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, |
1820 | const Diagnostic &Info) override; |
1821 | void clear() override; |
1822 | |
1823 | bool IncludeInDiagnosticCounts() const override; |
1824 | }; |
1825 | |
1826 | // Struct used for sending info about how a type should be printed. |
1827 | struct TemplateDiffTypes { |
1828 | intptr_t FromType; |
1829 | intptr_t ToType; |
1830 | LLVM_PREFERRED_TYPE(bool) |
1831 | unsigned PrintTree : 1; |
1832 | LLVM_PREFERRED_TYPE(bool) |
1833 | unsigned PrintFromType : 1; |
1834 | LLVM_PREFERRED_TYPE(bool) |
1835 | unsigned ElideType : 1; |
1836 | LLVM_PREFERRED_TYPE(bool) |
1837 | unsigned ShowColors : 1; |
1838 | |
1839 | // The printer sets this variable to true if the template diff was used. |
1840 | LLVM_PREFERRED_TYPE(bool) |
1841 | unsigned TemplateDiffUsed : 1; |
1842 | }; |
1843 | |
1844 | /// Special character that the diagnostic printer will use to toggle the bold |
1845 | /// attribute. The character itself will be not be printed. |
1846 | const char ToggleHighlight = 127; |
1847 | |
1848 | /// ProcessWarningOptions - Initialize the diagnostic client and process the |
1849 | /// warning options specified on the command line. |
1850 | void ProcessWarningOptions(DiagnosticsEngine &Diags, |
1851 | const DiagnosticOptions &Opts, |
1852 | bool ReportDiags = true); |
1853 | void EscapeStringForDiagnostic(StringRef Str, SmallVectorImpl<char> &OutStr); |
1854 | } // namespace clang |
1855 | |
1856 | #endif // LLVM_CLANG_BASIC_DIAGNOSTIC_H |
1857 | |