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