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