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