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