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