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