Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
clang 20.0.0git
DiagnosticIDs.cpp
Go to the documentation of this file.
1//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
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// This file implements the Diagnostic IDs-related interfaces.
10//
11//===----------------------------------------------------------------------===//
12
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringTable.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/Path.h"
22#include <map>
23#include <optional>
24using namespace clang;
25
26//===----------------------------------------------------------------------===//
27// Builtin Diagnostic information
28//===----------------------------------------------------------------------===//
29
30namespace {
31
32struct StaticDiagInfoRec;
33
34// Store the descriptions in a separate table to avoid pointers that need to
35// be relocated, and also decrease the amount of data needed on 64-bit
36// platforms. See "How To Write Shared Libraries" by Ulrich Drepper.
37struct StaticDiagInfoDescriptionStringTable {
38#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
39 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
40 char ENUM##_desc[sizeof(DESC)];
42#undef DIAG
43};
44
45const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
46#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
47 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
48 DESC,
50#undef DIAG
51};
52
53extern const StaticDiagInfoRec StaticDiagInfo[];
54
55// Stored separately from StaticDiagInfoRec to pack better. Otherwise,
56// StaticDiagInfoRec would have extra padding on 64-bit platforms.
57const uint32_t StaticDiagInfoDescriptionOffsets[] = {
58#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
59 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
60 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),
62#undef DIAG
63};
64
65// Diagnostic classes.
66enum DiagnosticClass {
67 CLASS_NOTE = 0x01,
68 CLASS_REMARK = 0x02,
69 CLASS_WARNING = 0x03,
70 CLASS_EXTENSION = 0x04,
71 CLASS_ERROR = 0x05
72};
73
74struct StaticDiagInfoRec {
75 uint16_t DiagID;
76 LLVM_PREFERRED_TYPE(diag::Severity)
77 uint8_t DefaultSeverity : 3;
78 LLVM_PREFERRED_TYPE(DiagnosticClass)
79 uint8_t Class : 3;
80 LLVM_PREFERRED_TYPE(DiagnosticIDs::SFINAEResponse)
81 uint8_t SFINAE : 2;
82 uint8_t Category : 6;
83 LLVM_PREFERRED_TYPE(bool)
84 uint8_t WarnNoWerror : 1;
85 LLVM_PREFERRED_TYPE(bool)
86 uint8_t WarnShowInSystemHeader : 1;
87 LLVM_PREFERRED_TYPE(bool)
88 uint8_t WarnShowInSystemMacro : 1;
89
90 uint16_t OptionGroupIndex : 15;
91 LLVM_PREFERRED_TYPE(bool)
92 uint16_t Deferrable : 1;
93
94 uint16_t DescriptionLen;
95
96 unsigned getOptionGroupIndex() const {
97 return OptionGroupIndex;
98 }
99
100 StringRef getDescription() const {
101 size_t MyIndex = this - &StaticDiagInfo[0];
102 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];
103 const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);
104 return StringRef(&Table[StringOffset], DescriptionLen);
105 }
106
107 diag::Flavor getFlavor() const {
108 return Class == CLASS_REMARK ? diag::Flavor::Remark
109 : diag::Flavor::WarningOrError;
110 }
111
112 bool operator<(const StaticDiagInfoRec &RHS) const {
113 return DiagID < RHS.DiagID;
114 }
115};
116
117#define STRINGIFY_NAME(NAME) #NAME
118#define VALIDATE_DIAG_SIZE(NAME) \
119 static_assert( \
120 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
121 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
122 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
123 STRINGIFY_NAME( \
124 DIAG_SIZE_##NAME) " is insufficient to contain all " \
125 "diagnostics, it may need to be made larger in " \
126 "DiagnosticIDs.h.");
127VALIDATE_DIAG_SIZE(COMMON)
128VALIDATE_DIAG_SIZE(DRIVER)
129VALIDATE_DIAG_SIZE(FRONTEND)
130VALIDATE_DIAG_SIZE(SERIALIZATION)
135VALIDATE_DIAG_SIZE(CROSSTU)
137VALIDATE_DIAG_SIZE(ANALYSIS)
138VALIDATE_DIAG_SIZE(REFACTORING)
139VALIDATE_DIAG_SIZE(INSTALLAPI)
140#undef VALIDATE_DIAG_SIZE
141#undef STRINGIFY_NAME
142
143const StaticDiagInfoRec StaticDiagInfo[] = {
144// clang-format off
145#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
146 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
147 { \
148 diag::ENUM, \
149 DEFAULT_SEVERITY, \
150 CLASS, \
151 DiagnosticIDs::SFINAE, \
152 CATEGORY, \
153 NOWERROR, \
154 SHOWINSYSHEADER, \
155 SHOWINSYSMACRO, \
156 GROUP, \
157 DEFERRABLE, \
158 STR_SIZE(DESC, uint16_t)},
159#include "clang/Basic/DiagnosticCommonKinds.inc"
160#include "clang/Basic/DiagnosticDriverKinds.inc"
161#include "clang/Basic/DiagnosticFrontendKinds.inc"
162#include "clang/Basic/DiagnosticSerializationKinds.inc"
163#include "clang/Basic/DiagnosticLexKinds.inc"
164#include "clang/Basic/DiagnosticParseKinds.inc"
165#include "clang/Basic/DiagnosticASTKinds.inc"
166#include "clang/Basic/DiagnosticCommentKinds.inc"
167#include "clang/Basic/DiagnosticCrossTUKinds.inc"
168#include "clang/Basic/DiagnosticSemaKinds.inc"
169#include "clang/Basic/DiagnosticAnalysisKinds.inc"
170#include "clang/Basic/DiagnosticRefactoringKinds.inc"
171#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
172// clang-format on
173#undef DIAG
174};
175
176} // namespace
177
178static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
179
180/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
181/// or null if the ID is invalid.
182static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
183 // Out of bounds diag. Can't be in the table.
184 using namespace diag;
185 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
186 return nullptr;
187
188 // Compute the index of the requested diagnostic in the static table.
189 // 1. Add the number of diagnostics in each category preceding the
190 // diagnostic and of the category the diagnostic is in. This gives us
191 // the offset of the category in the table.
192 // 2. Subtract the number of IDs in each category from our ID. This gives us
193 // the offset of the diagnostic in the category.
194 // This is cheaper than a binary search on the table as it doesn't touch
195 // memory at all.
196 unsigned Offset = 0;
197 unsigned ID = DiagID - DIAG_START_COMMON - 1;
198#define CATEGORY(NAME, PREV) \
199 if (DiagID > DIAG_START_##NAME) { \
200 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
201 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
202 }
203CATEGORY(DRIVER, COMMON)
204CATEGORY(FRONTEND, DRIVER)
205CATEGORY(SERIALIZATION, FRONTEND)
206CATEGORY(LEX, SERIALIZATION)
207CATEGORY(PARSE, LEX)
208CATEGORY(AST, PARSE)
209CATEGORY(COMMENT, AST)
210CATEGORY(CROSSTU, COMMENT)
211CATEGORY(SEMA, CROSSTU)
212CATEGORY(ANALYSIS, SEMA)
213CATEGORY(REFACTORING, ANALYSIS)
214CATEGORY(INSTALLAPI, REFACTORING)
215#undef CATEGORY
216
217 // Avoid out of bounds reads.
218 if (ID + Offset >= StaticDiagInfoSize)
219 return nullptr;
220
221 assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
222
223 const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
224 // If the diag id doesn't match we found a different diag, abort. This can
225 // happen when this function is called with an ID that points into a hole in
226 // the diagID space.
227 if (Found->DiagID != DiagID)
228 return nullptr;
229 return Found;
230}
231
234 diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
235
236 if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
237 Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
238
239 if (StaticInfo->WarnNoWerror) {
240 assert(Info.getSeverity() == diag::Severity::Warning &&
241 "Unexpected mapping with no-Werror bit!");
242 Info.setNoWarningAsError(true);
243 }
244 }
245
246 return Info;
247}
248
249/// getCategoryNumberForDiag - Return the category number that a specified
250/// DiagID belongs to, or 0 if no category.
252 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
253 return Info->Category;
254 return 0;
255}
256
257namespace {
258 // The diagnostic category names.
259 struct StaticDiagCategoryRec {
260 const char *NameStr;
261 uint8_t NameLen;
262
263 StringRef getName() const {
264 return StringRef(NameStr, NameLen);
265 }
266 };
267}
268
269static const StaticDiagCategoryRec CategoryNameTable[] = {
270#define GET_CATEGORY_TABLE
271#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
272#include "clang/Basic/DiagnosticGroups.inc"
273#undef GET_CATEGORY_TABLE
274 { nullptr, 0 }
275};
276
277/// getNumberOfCategories - Return the number of categories
279 return std::size(CategoryNameTable) - 1;
280}
281
282/// getCategoryNameFromID - Given a category ID, return the name of the
283/// category, an empty string if CategoryID is zero, or null if CategoryID is
284/// invalid.
285StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
286 if (CategoryID >= getNumberOfCategories())
287 return StringRef();
288 return CategoryNameTable[CategoryID].getName();
289}
290
291
292
295 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
296 return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
297 return SFINAE_Report;
298}
299
300bool DiagnosticIDs::isDeferrable(unsigned DiagID) {
301 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
302 return Info->Deferrable;
303 return false;
304}
305
306/// getBuiltinDiagClass - Return the class field of the diagnostic.
307///
308static unsigned getBuiltinDiagClass(unsigned DiagID) {
309 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
310 return Info->Class;
311 return ~0U;
312}
313
314//===----------------------------------------------------------------------===//
315// Custom Diagnostic information
316//===----------------------------------------------------------------------===//
317
318namespace clang {
319 namespace diag {
321 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;
322 std::vector<DiagDesc> DiagInfo;
323 std::map<DiagDesc, unsigned> DiagIDs;
324 public:
325
326 /// getDescription - Return the description of the specified custom
327 /// diagnostic.
328 StringRef getDescription(unsigned DiagID) const {
329 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
330 "Invalid diagnostic ID");
331 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
332 }
333
334 /// getLevel - Return the level of the specified custom diagnostic.
335 DiagnosticIDs::Level getLevel(unsigned DiagID) const {
336 assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
337 "Invalid diagnostic ID");
338 return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
339 }
340
341 unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
342 DiagnosticIDs &Diags) {
343 DiagDesc D(L, std::string(Message));
344 // Check to see if it already exists.
345 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);
346 if (I != DiagIDs.end() && I->first == D)
347 return I->second;
348
349 // If not, assign a new ID.
350 unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;
351 DiagIDs.insert(std::make_pair(D, ID));
352 DiagInfo.push_back(D);
353 return ID;
354 }
355 };
356
357 } // end diag namespace
358} // end clang namespace
359
360
361//===----------------------------------------------------------------------===//
362// Common Diagnostic implementation
363//===----------------------------------------------------------------------===//
364
366
368
369/// getCustomDiagID - Return an ID for a diagnostic with the specified message
370/// and level. If this is the first request for this diagnostic, it is
371/// registered and created, otherwise the existing ID is returned.
372///
373/// \param FormatString A fixed diagnostic format string that will be hashed and
374/// mapped to a unique DiagID.
375unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
376 if (!CustomDiagInfo)
377 CustomDiagInfo.reset(new diag::CustomDiagInfo());
378 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
379}
380
381
382/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
383/// level of the specified diagnostic ID is a Warning or Extension.
384/// This only works on builtin diagnostics, not custom ones, and is not legal to
385/// call on NOTEs.
387 return DiagID < diag::DIAG_UPPER_LIMIT &&
388 getBuiltinDiagClass(DiagID) != CLASS_ERROR;
389}
390
391/// Determine whether the given built-in diagnostic ID is a
392/// Note.
393bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
394 return DiagID < diag::DIAG_UPPER_LIMIT &&
395 getBuiltinDiagClass(DiagID) == CLASS_NOTE;
396}
397
398/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
399/// ID is for an extension of some sort. This also returns EnabledByDefault,
400/// which is set to indicate whether the diagnostic is ignored by default (in
401/// which case -pedantic enables it) or treated as a warning/error by default.
402///
404 bool &EnabledByDefault) {
405 if (DiagID >= diag::DIAG_UPPER_LIMIT ||
406 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
407 return false;
408
409 EnabledByDefault =
411 return true;
412}
413
415 if (DiagID >= diag::DIAG_UPPER_LIMIT)
416 return false;
417
419}
420
421/// getDescription - Given a diagnostic ID, return a description of the
422/// issue.
423StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
424 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
425 return Info->getDescription();
426 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
427 return CustomDiagInfo->getDescription(DiagID);
428}
429
431 switch (SV) {
442 }
443 llvm_unreachable("unexpected severity");
444}
445
446/// getDiagnosticLevel - Based on the way the client configured the
447/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
448/// by consumable the DiagnosticClient.
450DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
451 const DiagnosticsEngine &Diag) const {
452 // Handle custom diagnostics, which cannot be mapped.
453 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
454 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
455 return CustomDiagInfo->getLevel(DiagID);
456 }
457
458 unsigned DiagClass = getBuiltinDiagClass(DiagID);
459 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
460 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
461}
462
463/// Based on the way the client configured the Diagnostic
464/// object, classify the specified diagnostic ID into a Level, consumable by
465/// the DiagnosticClient.
466///
467/// \param Loc The source location we are interested in finding out the
468/// diagnostic state. Can be null in order to query the latest state.
470DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
471 const DiagnosticsEngine &Diag) const {
472 assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
473
474 // Specific non-error diagnostics may be mapped to various levels from ignored
475 // to error. Errors can only be mapped to fatal.
477
478 // Get the mapping information, or compute it lazily.
479 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
480 DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
481
482 // TODO: Can a null severity really get here?
483 if (Mapping.getSeverity() != diag::Severity())
484 Result = Mapping.getSeverity();
485
486 // Upgrade ignored diagnostics if -Weverything is enabled.
487 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
488 !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
490
491 // Ignore -pedantic diagnostics inside __extension__ blocks.
492 // (The diagnostics controlled by -pedantic are the extension diagnostics
493 // that are not enabled by default.)
494 bool EnabledByDefault = false;
495 bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
496 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
498
499 // For extension diagnostics that haven't been explicitly mapped, check if we
500 // should upgrade the diagnostic.
501 if (IsExtensionDiag && !Mapping.isUser())
502 Result = std::max(Result, State->ExtBehavior);
503
504 // At this point, ignored errors can no longer be upgraded.
506 return Result;
507
508 // Honor -w: this disables all messages which are not Error/Fatal by
509 // default (disregarding attempts to upgrade severity from Warning to Error),
510 // as well as disabling all messages which are currently mapped to Warning
511 // (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
512 // diagnostic.)
513 if (State->IgnoreAllWarnings) {
518 }
519
520 // If -Werror is enabled, map warnings to errors unless explicitly disabled.
522 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
524 }
525
526 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
527 // disabled.
529 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
531 }
532
533 // If explicitly requested, map fatal errors to errors.
535 DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)
537
538 // Rest of the mappings are only applicable for diagnostics associated with a
539 // SourceLocation, bail out early for others.
540 if (!Diag.hasSourceManager())
541 return Result;
542
543 const auto &SM = Diag.getSourceManager();
544 // Custom diagnostics always are emitted in system headers.
545 bool ShowInSystemHeader =
546 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
547
548 // If we are in a system header, we ignore it. We look at the diagnostic class
549 // because we also want to ignore extensions and warnings in -Werror and
550 // -pedantic-errors modes, which *map* warnings/extensions to errors.
551 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
552 SM.isInSystemHeader(SM.getExpansionLoc(Loc)))
554
555 // We also ignore warnings due to system macros
556 bool ShowInSystemMacro =
557 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;
558 if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&
559 SM.isInSystemMacro(Loc))
561
562 // Clang-diagnostics pragmas always take precedence over suppression mapping.
563 if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc))
565
566 return Result;
567}
568
569#define GET_DIAG_ARRAYS
570#include "clang/Basic/DiagnosticGroups.inc"
571#undef GET_DIAG_ARRAYS
572
573namespace {
574 struct WarningOption {
575 uint16_t NameOffset;
576 uint16_t Members;
577 uint16_t SubGroups;
578 StringRef Documentation;
579
580 StringRef getName() const { return DiagGroupNames[NameOffset]; }
581 };
582}
583
584// Second the table of options, sorted by name for fast binary lookup.
585static const WarningOption OptionTable[] = {
586#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
587 {FlagNameOffset, Members, SubGroups, Docs},
588#include "clang/Basic/DiagnosticGroups.inc"
589#undef DIAG_ENTRY
590};
591
592/// Given a diagnostic group ID, return its documentation.
594 return OptionTable[static_cast<int>(Group)].Documentation;
595}
596
598 return OptionTable[static_cast<int>(Group)].getName();
599}
600
601std::optional<diag::Group>
603 const auto *Found = llvm::partition_point(
604 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
605 if (Found == std::end(OptionTable) || Found->getName() != Name)
606 return std::nullopt;
607 return static_cast<diag::Group>(Found - OptionTable);
608}
609
610std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
611 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
612 return static_cast<diag::Group>(Info->getOptionGroupIndex());
613 return std::nullopt;
614}
615
616/// getWarningOptionForDiag - Return the lowest-level warning option that
617/// enables the specified diagnostic. If there is no -Wfoo flag that controls
618/// the diagnostic, this returns null.
619StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
620 if (auto G = getGroupForDiag(DiagID))
621 return getWarningOptionForGroup(*G);
622 return StringRef();
623}
624
625std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
626 std::vector<std::string> Res{"-W", "-Wno-"};
627 for (StringRef Name : DiagGroupNames) {
628 if (Name.empty())
629 continue;
630
631 Res.push_back((Twine("-W") + Name).str());
632 Res.push_back((Twine("-Wno-") + Name).str());
633 }
634
635 return Res;
636}
637
638/// Return \c true if any diagnostics were found in this group, even if they
639/// were filtered out due to having the wrong flavor.
641 const WarningOption *Group,
643 // An empty group is considered to be a warning group: we have empty groups
644 // for GCC compatibility, and GCC does not have remarks.
645 if (!Group->Members && !Group->SubGroups)
646 return Flavor == diag::Flavor::Remark;
647
648 bool NotFound = true;
649
650 // Add the members of the option diagnostic set.
651 const int16_t *Member = DiagArrays + Group->Members;
652 for (; *Member != -1; ++Member) {
653 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
654 NotFound = false;
655 Diags.push_back(*Member);
656 }
657 }
658
659 // Add the members of the subgroups.
660 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
661 for (; *SubGroups != (int16_t)-1; ++SubGroups)
662 NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
663 Diags);
664
665 return NotFound;
666}
667
668bool
670 SmallVectorImpl<diag::kind> &Diags) const {
671 if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
672 return ::getDiagnosticsInGroup(
673 Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
674 return true;
675}
676
678 std::vector<diag::kind> &Diags) {
679 for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
680 if (StaticDiagInfo[i].getFlavor() == Flavor)
681 Diags.push_back(StaticDiagInfo[i].DiagID);
682}
683
685 StringRef Group) {
686 StringRef Best;
687 unsigned BestDistance = Group.size() + 1; // Maximum threshold.
688 for (const WarningOption &O : OptionTable) {
689 // Don't suggest ignored warning flags.
690 if (!O.Members && !O.SubGroups)
691 continue;
692
693 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
694 if (Distance > BestDistance)
695 continue;
696
697 // Don't suggest groups that are not of this kind.
699 if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
700 continue;
701
702 if (Distance == BestDistance) {
703 // Two matches with the same distance, don't prefer one over the other.
704 Best = "";
705 } else if (Distance < BestDistance) {
706 // This is a better match.
707 Best = O.getName();
708 BestDistance = Distance;
709 }
710 }
711
712 return Best;
713}
714
715/// ProcessDiag - This is the method used to report a diagnostic that is
716/// finally fully formed.
717bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag,
718 const DiagnosticBuilder &DiagBuilder) const {
719 Diagnostic Info(&Diag, DiagBuilder);
720
721 assert(Diag.getClient() && "DiagnosticClient not set!");
722
723 // Figure out the diagnostic level of this message.
724 unsigned DiagID = Info.getID();
725 DiagnosticIDs::Level DiagLevel
726 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
727
728 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
729 // or diagnostics are suppressed.
730 if (DiagLevel >= DiagnosticIDs::Error) {
731 ++Diag.TrapNumErrorsOccurred;
732 if (isUnrecoverable(DiagID))
733 ++Diag.TrapNumUnrecoverableErrorsOccurred;
734 }
735
736 if (Diag.SuppressAllDiagnostics)
737 return false;
738
739 if (DiagLevel != DiagnosticIDs::Note) {
740 // Record that a fatal error occurred only when we see a second
741 // non-note diagnostic. This allows notes to be attached to the
742 // fatal error, but suppresses any diagnostics that follow those
743 // notes.
744 if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
745 Diag.FatalErrorOccurred = true;
746
747 Diag.LastDiagLevel = DiagLevel;
748 }
749
750 // If a fatal error has already been emitted, silence all subsequent
751 // diagnostics.
752 if (Diag.FatalErrorOccurred) {
753 if (DiagLevel >= DiagnosticIDs::Error &&
754 Diag.Client->IncludeInDiagnosticCounts()) {
755 ++Diag.NumErrors;
756 }
757
758 return false;
759 }
760
761 // If the client doesn't care about this message, don't issue it. If this is
762 // a note and the last real diagnostic was ignored, ignore it too.
763 if (DiagLevel == DiagnosticIDs::Ignored ||
764 (DiagLevel == DiagnosticIDs::Note &&
765 Diag.LastDiagLevel == DiagnosticIDs::Ignored))
766 return false;
767
768 if (DiagLevel >= DiagnosticIDs::Error) {
769 if (isUnrecoverable(DiagID))
770 Diag.UnrecoverableErrorOccurred = true;
771
772 // Warnings which have been upgraded to errors do not prevent compilation.
773 if (isDefaultMappingAsError(DiagID))
774 Diag.UncompilableErrorOccurred = true;
775
776 Diag.ErrorOccurred = true;
777 if (Diag.Client->IncludeInDiagnosticCounts()) {
778 ++Diag.NumErrors;
779 }
780
781 // If we've emitted a lot of errors, emit a fatal error instead of it to
782 // stop a flood of bogus errors.
783 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
784 DiagLevel == DiagnosticIDs::Error) {
785 Diag.Report(diag::fatal_too_many_errors);
786 return false;
787 }
788 }
789
790 // Make sure we set FatalErrorOccurred to ensure that the notes from the
791 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
792 if (Info.getID() == diag::fatal_too_many_errors)
793 Diag.FatalErrorOccurred = true;
794 // Finally, report it.
795 EmitDiag(Diag, DiagBuilder, DiagLevel);
796 return true;
797}
798
799void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag,
800 const DiagnosticBuilder &DiagBuilder,
801 Level DiagLevel) const {
802 Diagnostic Info(&Diag, DiagBuilder);
803 assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
804
805 Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
806 if (Diag.Client->IncludeInDiagnosticCounts()) {
807 if (DiagLevel == DiagnosticIDs::Warning)
808 ++Diag.NumWarnings;
809 }
810}
811
812bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
813 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
814 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
815 // Custom diagnostics.
816 return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
817 }
818
819 // Only errors may be unrecoverable.
820 if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
821 return false;
822
823 if (DiagID == diag::err_unavailable ||
824 DiagID == diag::err_unavailable_message)
825 return false;
826
827 // Currently we consider all ARC errors as recoverable.
828 if (isARCDiagnostic(DiagID))
829 return false;
830
831 if (isCodegenABICheckDiagnostic(DiagID))
832 return false;
833
834 return true;
835}
836
837bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
838 unsigned cat = getCategoryNumberForDiag(DiagID);
839 return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");
840}
841
843 unsigned cat = getCategoryNumberForDiag(DiagID);
844 return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check";
845}
Includes all the separate Diagnostic headers & some related helpers.
#define SM(sm)
Definition: Cuda.cpp:85
const Decl * D
#define COMMENT(CLASS, PARENT)
Definition: Comment.h:54
static const StaticDiagInfoRec * GetDiagInfo(unsigned DiagID)
GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, or null if the ID is inval...
static DiagnosticIDs::Level toLevel(diag::Severity SV)
#define VALIDATE_DIAG_SIZE(NAME)
#define CATEGORY(NAME, PREV)
static const unsigned StaticDiagInfoSize
static unsigned getBuiltinDiagClass(unsigned DiagID)
getBuiltinDiagClass - Return the class field of the diagnostic.
static const WarningOption OptionTable[]
static bool getDiagnosticsInGroup(diag::Flavor Flavor, const WarningOption *Group, SmallVectorImpl< diag::kind > &Diags)
Return true if any diagnostics were found in this group, even if they were filtered out due to having...
static const StaticDiagCategoryRec CategoryNameTable[]
Defines the Diagnostic IDs-related interfaces.
int Category
Definition: Format.cpp:3056
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
static std::string getName(const CallEvent &Call)
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the SourceManager interface.
unsigned NameLen
A little helper class used to produce diagnostics.
Definition: Diagnostic.h:1220
Used for handling and querying diagnostic IDs.
static bool isBuiltinExtensionDiag(unsigned DiagID)
Determine whether the given built-in diagnostic ID is for an extension of some sort.
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static unsigned getNumberOfCategories()
Return the number of diagnostic categories.
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name.
bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, SmallVectorImpl< diag::kind > &Diags) const
Get the set of all diagnostic IDs in the group with the given name.
static std::vector< std::string > getDiagnosticFlags()
Get the string of all diagnostic flags.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID)
Determines whether the given built-in diagnostic ID is for an error that is suppressed if it occurs d...
static bool isDefaultMappingAsError(unsigned DiagID)
Return true if the specified diagnostic is mapped to errors by default.
static bool isBuiltinNote(unsigned DiagID)
Determine whether the given built-in diagnostic ID is a Note.
static bool isBuiltinWarningOrExtension(unsigned DiagID)
Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension.
static bool isCodegenABICheckDiagnostic(unsigned DiagID)
Return true if a given diagnostic is a codegen-time ABI check.
StringRef getDescription(unsigned DiagID) const
Given a diagnostic ID, return a description of the issue.
SFINAEResponse
Enumeration describing how the emission of a diagnostic should be treated when it occurs during C++ t...
@ SFINAE_Report
The diagnostic should be reported.
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
static StringRef getWarningOptionDocumentation(diag::Group GroupID)
Given a diagnostic group ID, return its documentation.
static std::optional< diag::Group > getGroupForWarningOption(StringRef)
Given a group ID, returns the flag that toggles the group.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static std::optional< diag::Group > getGroupForDiag(unsigned DiagID)
Return the lowest-level group that contains the specified diagnostic.
static StringRef getWarningOptionForGroup(diag::Group)
Given a group ID, returns the flag that toggles the group.
static bool isARCDiagnostic(unsigned DiagID)
Return true if a given diagnostic falls into an ARC diagnostic category.
Level
The level of the diagnostic, after it has been through mapping.
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
static DiagnosticMapping getDefaultMapping(unsigned DiagID)
Get the default mapping for this diagnostic.
unsigned getCustomDiagID(Level L, StringRef FormatString)
Return an ID for a diagnostic with the specified format string and level.
static bool isDeferrable(unsigned DiagID)
Whether the diagnostic message can be deferred.
bool hasNoErrorAsFatal() const
void setNoWarningAsError(bool Value)
void setSeverity(diag::Severity Value)
diag::Severity getSeverity() const
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, bool IsPragma)
bool hasNoWarningAsError() const
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Definition: Diagnostic.h:1512
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:231
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:234
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
StringRef getDescription(unsigned DiagID) const
getDescription - Return the description of the specified custom diagnostic.
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, DiagnosticIDs &Diags)
DiagnosticIDs::Level getLevel(unsigned DiagID) const
getLevel - Return the level of the specified custom diagnostic.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
Definition: DiagnosticIDs.h:87
@ Warning
Present this diagnostic as a warning.
@ Fatal
Present this diagnostic as a fatal error.
@ Error
Present this diagnostic as an error.
@ Remark
Present this diagnostic as a remark.
@ Ignored
Do not present this diagnostic, ignore it.
Flavor
Flavors of diagnostics we can emit.
Definition: DiagnosticIDs.h:98
@ Remark
A diagnostic that indicates normal progress through compilation.
The JSON file list parser is used to communicate input to InstallAPI.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Result
The result type of a method or function.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
unsigned int uint32_t