clang 8.0.0

DiagnosticIDs.cpp
Go to the documentation of this file.
1 //===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Diagnostic IDs-related interfaces.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Basic/DiagnosticIDs.h"
15 #include "clang/Basic/AllDiagnostics.h"
16 #include "clang/Basic/DiagnosticCategories.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include <map>
22 using namespace clang;
23
24 //===----------------------------------------------------------------------===//
25 // Builtin Diagnostic information
26 //===----------------------------------------------------------------------===//
27
28 namespace {
29
30 // Diagnostic classes.
31 enum {
32 CLASS_NOTE = 0x01,
33 CLASS_REMARK = 0x02,
34 CLASS_WARNING = 0x03,
35 CLASS_EXTENSION = 0x04,
36 CLASS_ERROR = 0x05
37 };
38
39 struct StaticDiagInfoRec {
40 uint16_t DiagID;
41 unsigned DefaultSeverity : 3;
42 unsigned Class : 3;
43 unsigned SFINAE : 2;
44 unsigned WarnNoWerror : 1;
45 unsigned WarnShowInSystemHeader : 1;
46 unsigned Category : 6;
47
48 uint16_t OptionGroupIndex;
49
50 uint16_t DescriptionLen;
51 const char *DescriptionStr;
52
53 unsigned getOptionGroupIndex() const {
54 return OptionGroupIndex;
55 }
56
57 StringRef getDescription() const {
58 return StringRef(DescriptionStr, DescriptionLen);
59 }
60
61 diag::Flavor getFlavor() const {
62 return Class == CLASS_REMARK ? diag::Flavor::Remark
63 : diag::Flavor::WarningOrError;
64 }
65
66 bool operator<(const StaticDiagInfoRec &RHS) const {
67 return DiagID < RHS.DiagID;
68 }
69 };
70
71 #define STRINGIFY_NAME(NAME) #NAME
72 #define VALIDATE_DIAG_SIZE(NAME) \
73 static_assert( \
74 static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \
75 static_cast<unsigned>(diag::DIAG_START_##NAME) + \
76 static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \
77 STRINGIFY_NAME( \
78 DIAG_SIZE_##NAME) " is insufficient to contain all " \
79 "diagnostics, it may need to be made larger in " \
80 "DiagnosticIDs.h.");
81 VALIDATE_DIAG_SIZE(COMMON)
82 VALIDATE_DIAG_SIZE(DRIVER)
83 VALIDATE_DIAG_SIZE(FRONTEND)
84 VALIDATE_DIAG_SIZE(SERIALIZATION)
85 VALIDATE_DIAG_SIZE(LEX)
86 VALIDATE_DIAG_SIZE(PARSE)
87 VALIDATE_DIAG_SIZE(AST)
88 VALIDATE_DIAG_SIZE(COMMENT)
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.
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
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.
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
204 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 &
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
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.
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
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 ///
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.
278 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.
285 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
291 unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,
292 DiagnosticIDs &Diags) {
293 DiagDesc D(L, 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
315 DiagnosticIDs::DiagnosticIDs() { CustomDiagInfo = nullptr; }
316
317 DiagnosticIDs::~DiagnosticIDs() {
318 delete CustomDiagInfo;
319 }
320
321 /// getCustomDiagID - Return an ID for a diagnostic with the specified message
322 /// and level. If this is the first request for this diagnostic, it is
323 /// registered and created, otherwise the existing ID is returned.
324 ///
325 /// \param FormatString A fixed diagnostic format string that will be hashed and
326 /// mapped to a unique DiagID.
327 unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
328 if (!CustomDiagInfo)
329 CustomDiagInfo = new diag::CustomDiagInfo();
330 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
331 }
332
333
334 /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
335 /// level of the specified diagnostic ID is a Warning or Extension.
336 /// This only works on builtin diagnostics, not custom ones, and is not legal to
337 /// call on NOTEs.
338 bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
339 return DiagID < diag::DIAG_UPPER_LIMIT &&
340 getBuiltinDiagClass(DiagID) != CLASS_ERROR;
341 }
342
343 /// Determine whether the given built-in diagnostic ID is a
344 /// Note.
345 bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
346 return DiagID < diag::DIAG_UPPER_LIMIT &&
347 getBuiltinDiagClass(DiagID) == CLASS_NOTE;
348 }
349
350 /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
351 /// ID is for an extension of some sort. This also returns EnabledByDefault,
352 /// which is set to indicate whether the diagnostic is ignored by default (in
353 /// which case -pedantic enables it) or treated as a warning/error by default.
354 ///
355 bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
356 bool &EnabledByDefault) {
357 if (DiagID >= diag::DIAG_UPPER_LIMIT ||
358 getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
359 return false;
360
361 EnabledByDefault =
362 GetDefaultDiagMapping(DiagID).getSeverity() != diag::Severity::Ignored;
363 return true;
364 }
365
366 bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
367 if (DiagID >= diag::DIAG_UPPER_LIMIT)
368 return false;
369
370 return GetDefaultDiagMapping(DiagID).getSeverity() >= diag::Severity::Error;
371 }
372
373 /// getDescription - Given a diagnostic ID, return a description of the
374 /// issue.
375 StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
376 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
377 return Info->getDescription();
378 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
379 return CustomDiagInfo->getDescription(DiagID);
380 }
381
382 static DiagnosticIDs::Level toLevel(diag::Severity SV) {
383 switch (SV) {
384 case diag::Severity::Ignored:
385 return DiagnosticIDs::Ignored;
386 case diag::Severity::Remark:
387 return DiagnosticIDs::Remark;
388 case diag::Severity::Warning:
389 return DiagnosticIDs::Warning;
390 case diag::Severity::Error:
391 return DiagnosticIDs::Error;
392 case diag::Severity::Fatal:
393 return DiagnosticIDs::Fatal;
394 }
395 llvm_unreachable("unexpected severity");
396 }
397
398 /// getDiagnosticLevel - Based on the way the client configured the
399 /// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
400 /// by consumable the DiagnosticClient.
401 DiagnosticIDs::Level
402 DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
403 const DiagnosticsEngine &Diag) const {
404 // Handle custom diagnostics, which cannot be mapped.
405 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
406 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
407 return CustomDiagInfo->getLevel(DiagID);
408 }
409
410 unsigned DiagClass = getBuiltinDiagClass(DiagID);
411 if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
412 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
413 }
414
415 /// Based on the way the client configured the Diagnostic
416 /// object, classify the specified diagnostic ID into a Level, consumable by
417 /// the DiagnosticClient.
418 ///
419 /// \param Loc The source location we are interested in finding out the
420 /// diagnostic state. Can be null in order to query the latest state.
421 diag::Severity
422 DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
423 const DiagnosticsEngine &Diag) const {
424 assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
425
426 // Specific non-error diagnostics may be mapped to various levels from ignored
427 // to error. Errors can only be mapped to fatal.
428 diag::Severity Result = diag::Severity::Fatal;
429
430 // Get the mapping information, or compute it lazily.
431 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
432 DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
433
434 // TODO: Can a null severity really get here?
435 if (Mapping.getSeverity() != diag::Severity())
436 Result = Mapping.getSeverity();
437
438 // Upgrade ignored diagnostics if -Weverything is enabled.
439 if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
440 !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
441 Result = diag::Severity::Warning;
442
443 // Ignore -pedantic diagnostics inside __extension__ blocks.
444 // (The diagnostics controlled by -pedantic are the extension diagnostics
445 // that are not enabled by default.)
446 bool EnabledByDefault = false;
447 bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
448 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
449 return diag::Severity::Ignored;
450
451 // For extension diagnostics that haven't been explicitly mapped, check if we
452 // should upgrade the diagnostic.
453 if (IsExtensionDiag && !Mapping.isUser())
454 Result = std::max(Result, State->ExtBehavior);
455
456 // At this point, ignored errors can no longer be upgraded.
457 if (Result == diag::Severity::Ignored)
458 return Result;
459
460 // Honor -w, which is lower in priority than pedantic-errors, but higher than
461 // -Werror.
462 // FIXME: Under GCC, this also suppresses warnings that have been mapped to
463 // errors by -W flags and #pragma diagnostic.
464 if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)
465 return diag::Severity::Ignored;
466
467 // If -Werror is enabled, map warnings to errors unless explicitly disabled.
468 if (Result == diag::Severity::Warning) {
469 if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
470 Result = diag::Severity::Error;
471 }
472
473 // If -Wfatal-errors is enabled, map errors to fatal unless explicitly
474 // disabled.
475 if (Result == diag::Severity::Error) {
476 if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
477 Result = diag::Severity::Fatal;
478 }
479
480 // Custom diagnostics always are emitted in system headers.
481 bool ShowInSystemHeader =
482 !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
483
484 // If we are in a system header, we ignore it. We look at the diagnostic class
485 // because we also want to ignore extensions and warnings in -Werror and
486 // -pedantic-errors modes, which *map* warnings/extensions to errors.
487 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
488 Diag.getSourceManager().isInSystemHeader(
489 Diag.getSourceManager().getExpansionLoc(Loc)))
490 return diag::Severity::Ignored;
491
492 return Result;
493 }
494
495 #define GET_DIAG_ARRAYS
496 #include "clang/Basic/DiagnosticGroups.inc"
497 #undef GET_DIAG_ARRAYS
498
499 namespace {
500 struct WarningOption {
501 uint16_t NameOffset;
502 uint16_t Members;
503 uint16_t SubGroups;
504
505 // String is stored with a pascal-style length byte.
506 StringRef getName() const {
507 return StringRef(DiagGroupNames + NameOffset + 1,
508 DiagGroupNames[NameOffset]);
509 }
510 };
511 }
512
513 // Second the table of options, sorted by name for fast binary lookup.
514 static const WarningOption OptionTable[] = {
515 #define GET_DIAG_TABLE
516 #include "clang/Basic/DiagnosticGroups.inc"
517 #undef GET_DIAG_TABLE
518 };
519
520 /// getWarningOptionForDiag - Return the lowest-level warning option that
521 /// enables the specified diagnostic. If there is no -Wfoo flag that controls
522 /// the diagnostic, this returns null.
523 StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
524 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
525 return OptionTable[Info->getOptionGroupIndex()].getName();
526 return StringRef();
527 }
528
529 std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
530 std::vector<std::string> Res;
531 for (size_t I = 1; DiagGroupNames[I] != '\0';) {
532 std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
533 I += DiagGroupNames[I] + 1;
534 Res.push_back("-W" + Diag);
535 Res.push_back("-Wno-" + Diag);
536 }
537
538 return Res;
539 }
540
541 /// Return \c true if any diagnostics were found in this group, even if they
542 /// were filtered out due to having the wrong flavor.
543 static bool getDiagnosticsInGroup(diag::Flavor Flavor,
544 const WarningOption *Group,
545 SmallVectorImpl<diag::kind> &Diags) {
546 // An empty group is considered to be a warning group: we have empty groups
547 // for GCC compatibility, and GCC does not have remarks.
548 if (!Group->Members && !Group->SubGroups)
549 return Flavor == diag::Flavor::Remark;
550
551 bool NotFound = true;
552
553 // Add the members of the option diagnostic set.
554 const int16_t *Member = DiagArrays + Group->Members;
555 for (; *Member != -1; ++Member) {
556 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
557 NotFound = false;
558 Diags.push_back(*Member);
559 }
560 }
561
562 // Add the members of the subgroups.
563 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
564 for (; *SubGroups != (int16_t)-1; ++SubGroups)
565 NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
566 Diags);
567
568 return NotFound;
569 }
570
571 bool
572 DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
573 SmallVectorImpl<diag::kind> &Diags) const {
574 auto Found = std::lower_bound(std::begin(OptionTable), std::end(OptionTable),
575 Group,
576 [](const WarningOption &LHS, StringRef RHS) {
577 return LHS.getName() < RHS;
578 });
579 if (Found == std::end(OptionTable) || Found->getName() != Group)
580 return true; // Option not found.
581
582 return ::getDiagnosticsInGroup(Flavor, Found, Diags);
583 }
584
585 void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
586 std::vector<diag::kind> &Diags) {
587 for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
588 if (StaticDiagInfo[i].getFlavor() == Flavor)
589 Diags.push_back(StaticDiagInfo[i].DiagID);
590 }
591
592 StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
593 StringRef Group) {
594 StringRef Best;
595 unsigned BestDistance = Group.size() + 1; // Sanity threshold.
596 for (const WarningOption &O : OptionTable) {
597 // Don't suggest ignored warning flags.
598 if (!O.Members && !O.SubGroups)
599 continue;
600
601 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);
602 if (Distance > BestDistance)
603 continue;
604
605 // Don't suggest groups that are not of this kind.
606 llvm::SmallVector<diag::kind, 8> Diags;
607 if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())
608 continue;
609
610 if (Distance == BestDistance) {
611 // Two matches with the same distance, don't prefer one over the other.
612 Best = "";
613 } else if (Distance < BestDistance) {
614 // This is a better match.
615 Best = O.getName();
616 BestDistance = Distance;
617 }
618 }
619
620 return Best;
621 }
622
623 /// ProcessDiag - This is the method used to report a diagnostic that is
624 /// finally fully formed.
625 bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
626 Diagnostic Info(&Diag);
627
628 assert(Diag.getClient() && "DiagnosticClient not set!");
629
630 // Figure out the diagnostic level of this message.
631 unsigned DiagID = Info.getID();
632 DiagnosticIDs::Level DiagLevel
633 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
634
635 // Update counts for DiagnosticErrorTrap even if a fatal error occurred
636 // or diagnostics are suppressed.
637 if (DiagLevel >= DiagnosticIDs::Error) {
638 ++Diag.TrapNumErrorsOccurred;
639 if (isUnrecoverable(DiagID))
640 ++Diag.TrapNumUnrecoverableErrorsOccurred;
641 }
642
643 if (Diag.SuppressAllDiagnostics)
644 return false;
645
646 if (DiagLevel != DiagnosticIDs::Note) {
647 // Record that a fatal error occurred only when we see a second
648 // non-note diagnostic. This allows notes to be attached to the
649 // fatal error, but suppresses any diagnostics that follow those
650 // notes.
651 if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)
652 Diag.FatalErrorOccurred = true;
653
654 Diag.LastDiagLevel = DiagLevel;
655 }
656
657 // If a fatal error has already been emitted, silence all subsequent
658 // diagnostics.
659 if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {
660 if (DiagLevel >= DiagnosticIDs::Error &&
661 Diag.Client->IncludeInDiagnosticCounts()) {
662 ++Diag.NumErrors;
663 }
664
665 return false;
666 }
667
668 // If the client doesn't care about this message, don't issue it. If this is
669 // a note and the last real diagnostic was ignored, ignore it too.
670 if (DiagLevel == DiagnosticIDs::Ignored ||
671 (DiagLevel == DiagnosticIDs::Note &&
672 Diag.LastDiagLevel == DiagnosticIDs::Ignored))
673 return false;
674
675 if (DiagLevel >= DiagnosticIDs::Error) {
676 if (isUnrecoverable(DiagID))
677 Diag.UnrecoverableErrorOccurred = true;
678
679 // Warnings which have been upgraded to errors do not prevent compilation.
680 if (isDefaultMappingAsError(DiagID))
681 Diag.UncompilableErrorOccurred = true;
682
683 Diag.ErrorOccurred = true;
684 if (Diag.Client->IncludeInDiagnosticCounts()) {
685 ++Diag.NumErrors;
686 }
687
688 // If we've emitted a lot of errors, emit a fatal error instead of it to
689 // stop a flood of bogus errors.
690 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&
691 DiagLevel == DiagnosticIDs::Error) {
692 Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);
693 return false;
694 }
695 }
696
697 // Make sure we set FatalErrorOccurred to ensure that the notes from the
698 // diagnostic that caused `fatal_too_many_errors` won't be emitted.
699 if (Diag.CurDiagID == diag::fatal_too_many_errors)
700 Diag.FatalErrorOccurred = true;
701 // Finally, report it.
702 EmitDiag(Diag, DiagLevel);
703 return true;
704 }
705
706 void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
707 Diagnostic Info(&Diag);
708 assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
709
710 Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
711 if (Diag.Client->IncludeInDiagnosticCounts()) {
712 if (DiagLevel == DiagnosticIDs::Warning)
713 ++Diag.NumWarnings;
714 }
715
716 Diag.CurDiagID = ~0U;
717 }
718
719 bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
720 if (DiagID >= diag::DIAG_UPPER_LIMIT) {
721 assert(CustomDiagInfo && "Invalid CustomDiagInfo");
722 // Custom diagnostics.
723 return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
724 }
725
726 // Only errors may be unrecoverable.
727 if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)
728 return false;
729
730 if (DiagID == diag::err_unavailable ||
731 DiagID == diag::err_unavailable_message)
732 return false;
733
734 // Currently we consider all ARC errors as recoverable.
735 if (isARCDiagnostic(DiagID))
736 return false;
737
738 return true;
739 }
740
741 bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
742 unsigned cat = getCategoryNumberForDiag(DiagID);
743 return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
744 }
clang::DiagnosticIDs::getCategoryNumberForDiag
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
Definition: DiagnosticIDs.cpp:192
clang::diag::Flavor::WarningOrError
A diagnostic that indicates a problem or potential problem.
clang::diag::CustomDiagInfo::getOrCreateDiagID
unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, DiagnosticIDs &Diags)
Definition: DiagnosticIDs.cpp:291
clang::Builtin::ID
ID
Definition: Builtins.h:49
Diag
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Definition: LiteralSupport.cpp:78
clang::DiagnosticsEngine::getClient
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:510
clang::if
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
GetDefaultDiagMapping
static DiagnosticMapping GetDefaultDiagMapping(unsigned DiagID)
Definition: DiagnosticIDs.cpp:173
clang::DiagnosticsEngine::getSourceManager
SourceManager & getSourceManager() const
Definition: Diagnostic.h:522
clang::diag::CustomDiagInfo::getLevel
DiagnosticIDs::Level getLevel(unsigned DiagID) const
getLevel - Return the level of the specified custom diagnostic.
Definition: DiagnosticIDs.cpp:285
SourceManager.h
Defines the SourceManager interface.
clang::DiagnosticIDs::DiagnosticIDs
DiagnosticIDs()
Definition: DiagnosticIDs.cpp:315
getBuiltinDiagClass
static unsigned getBuiltinDiagClass(unsigned DiagID)
getBuiltinDiagClass - Return the class field of the diagnostic.
Definition: DiagnosticIDs.cpp:258
toLevel
static DiagnosticIDs::Level toLevel(diag::Severity SV)
Definition: DiagnosticIDs.cpp:382
clang::DiagnosticIDs::getCategoryNameFromID
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
Definition: DiagnosticIDs.cpp:241
clang::DiagnosticIDs::Ignored
Definition: DiagnosticIDs.h:168
clang::DiagnosticConsumer::IncludeInDiagnosticCounts
virtual bool IncludeInDiagnosticCounts() const
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
Definition: Diagnostic.cpp:1116
clang::DiagnosticMapping
Definition: DiagnosticIDs.h:99
clang::diag::Severity
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
Definition: DiagnosticIDs.h:80
CATEGORY
#define CATEGORY(NAME, PREV)
clang::DiagnosticsEngine::SetDelayedDiagnostic
void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1="", StringRef Arg2="")
Set the "delayed" diagnostic that will be emitted once the current diagnostic completes.
Definition: Diagnostic.cpp:148
clang::index::SymbolKind::Class
clang::CodeGen::getName
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
clang::Diagnostic::getID
unsigned getID() const
Definition: Diagnostic.h:1326
clang::DiagnosticIDs::Note
Definition: DiagnosticIDs.h:168
AllDiagnostics.h
Includes all the separate Diagnostic headers & some related helpers.
State
LineState State
Definition: UnwrappedLineFormatter.cpp:877
StaticDiagInfo
static const StaticDiagInfoRec StaticDiagInfo[]
Definition: DiagnosticIDs.cpp:97
getDiagnosticsInGroup
static bool getDiagnosticsInGroup(diag::Flavor Flavor, const WarningOption *Group, SmallVectorImpl< diag::kind > &Diags)
Return true if any diagnostics were found in this group, even if they were filtered out due to having...
Definition: DiagnosticIDs.cpp:543
Category
int Category
Definition: Format.cpp:1632
clang::DiagnosticMapping::isUser
bool isUser() const
Definition: DiagnosticIDs.h:123
clang::DiagnosticMapping::hasNoErrorAsFatal
bool hasNoErrorAsFatal() const
Definition: DiagnosticIDs.h:134
llvm::SmallVectorImpl
Definition: LLVM.h:37
clang::DiagnosticIDs::getNumberOfCategories
static unsigned getNumberOfCategories()
Return the number of diagnostic categories.
Definition: DiagnosticIDs.cpp:234
clang::DiagnosticIDs::getNearestOption
static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)
Get the diagnostic option with the closest edit distance to the given group name. ...
Definition: DiagnosticIDs.cpp:592
clang::Diagnostic::getLocation
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1327
clang::SourceManager::getExpansionLoc
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Definition: SourceManager.h:1117
clang::DiagnosticsEngine
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
clang::DiagnosticIDs::isBuiltinWarningOrExtension
static bool isBuiltinWarningOrExtension(unsigned DiagID)
Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension...
Definition: DiagnosticIDs.cpp:338
clang::DiagnosticMapping::getSeverity
diag::Severity getSeverity() const
Definition: DiagnosticIDs.h:120
clang::DiagnosticIDs::~DiagnosticIDs
~DiagnosticIDs()
Definition: DiagnosticIDs.cpp:317
clang::diag::Severity::Error
Present this diagnostic as an error.
GetDiagInfo
static const StaticDiagInfoRec * GetDiagInfo(unsigned DiagID)
GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, or null if the ID is inval...
Definition: DiagnosticIDs.cpp:124
Offset
unsigned Offset
Definition: Format.cpp:1631
DiagnosticCategories.h
clang::DiagnosticIDs::isBuiltinExtensionDiag
static bool isBuiltinExtensionDiag(unsigned DiagID)
Determine whether the given built-in diagnostic ID is for an extension of some sort.
Definition: DiagnosticIDs.h:213
clang::SourceManager::isInSystemHeader
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
Definition: SourceManager.h:1445
VALIDATE_DIAG_SIZE
#define VALIDATE_DIAG_SIZE(NAME)
Definition: DiagnosticIDs.cpp:72
clang::DiagnosticIDs::getWarningOptionForDiag
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Definition: DiagnosticIDs.cpp:523
clang::ObjCSubstitutionContext::Result
The result type of a method or function.
clang::diag::DIAG_UPPER_LIMIT
Definition: DiagnosticIDs.h:58
COMMENT
#define COMMENT(CLASS, PARENT)
Definition: Comment.h:188
clang::DiagnosticIDs::Warning
Definition: DiagnosticIDs.h:168
clang::DiagnosticIDs::getAllDiagnostics
static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)
Get the set of all diagnostic IDs.
Definition: DiagnosticIDs.cpp:585
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::diag::CustomDiagInfo
Definition: DiagnosticIDs.cpp:270
OptionTable
static const WarningOption OptionTable[]
Definition: DiagnosticIDs.cpp:514
clang::DiagnosticIDs::getDiagnosticFlags
static std::vector< std::string > getDiagnosticFlags()
Get the string of all diagnostic flags.
Definition: DiagnosticIDs.cpp:529
llvm::SmallVector
Definition: LLVM.h:36
clang::DiagnosticConsumer::HandleDiagnostic
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
Definition: Diagnostic.cpp:533
clang::diag::Flavor
Flavor
Flavors of diagnostics we can emit.
Definition: DiagnosticIDs.h:91
clang::operator<
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
Definition: DeclarationName.h:541
clang::DiagnosticMapping::Make
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, bool IsPragma)
Definition: DiagnosticIDs.h:108
clang::DiagnosticIDs::isBuiltinNote
static bool isBuiltinNote(unsigned DiagID)
Determine whether the given built-in diagnostic ID is a Note.
Definition: DiagnosticIDs.cpp:345
clang::DiagnosticIDs::getCustomDiagID
unsigned getCustomDiagID(Level L, StringRef FormatString)
Return an ID for a diagnostic with the specified format string and level.
Definition: DiagnosticIDs.cpp:327
clang::DiagnosticIDs::getDiagnosticsInGroup
bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, SmallVectorImpl< diag::kind > &Diags) const
Get the set of all diagnostic IDs in the group with the given name.
Definition: DiagnosticIDs.cpp:572
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:22
clang::SourceLocation::isValid
bool isValid() const
Return true if this is a valid SourceLocation object.
Definition: SourceLocation.h:108
clang::diag::Severity::Remark
Present this diagnostic as a remark.
clang::diag::CustomDiagInfo::getDescription
StringRef getDescription(unsigned DiagID) const
getDescription - Return the description of the specified custom diagnostic.
Definition: DiagnosticIDs.cpp:278
clang::DiagnosticIDs::Level
Level
The level of the diagnostic, after it has been through mapping.
Definition: DiagnosticIDs.h:167
clang::DiagnosticIDs
Used for handling and querying diagnostic IDs.
Definition: DiagnosticIDs.h:164
clang::DiagnosticIDs::Fatal
Definition: DiagnosticIDs.h:168
StaticDiagInfoSize
static const unsigned StaticDiagInfoSize
Definition: DiagnosticIDs.cpp:120
clang::DiagnosticIDs::Remark
Definition: DiagnosticIDs.h:168
clang::DiagnosticIDs::isDefaultMappingAsError
static bool isDefaultMappingAsError(unsigned DiagID)
Return true if the specified diagnostic is mapped to errors by default.
Definition: DiagnosticIDs.cpp:366
CategoryNameTable
static const StaticDiagCategoryRec CategoryNameTable[]
Definition: DiagnosticIDs.cpp:225
clang::DiagnosticMapping::setSeverity
void setSeverity(diag::Severity Value)
Definition: DiagnosticIDs.h:121
clang::DiagnosticIDs::getDescription
StringRef getDescription(unsigned DiagID) const
Given a diagnostic ID, return a description of the issue.
Definition: DiagnosticIDs.cpp:375
clang::DiagnosticIDs::isARCDiagnostic
static bool isARCDiagnostic(unsigned DiagID)
Return true if a given diagnostic falls into an ARC diagnostic category.
Definition: DiagnosticIDs.cpp:741
clang::DiagnosticIDs::getDiagnosticSFINAEResponse
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID)
Determines whether the given built-in diagnostic ID is for an error that is suppressed if it occurs d...
Definition: DiagnosticIDs.cpp:250
clang::DiagnosticIDs::SFINAEResponse
SFINAEResponse
Enumeration describing how the emission of a diagnostic should be treated when it occurs during C++ t...
Definition: DiagnosticIDs.h:250
ANALYSIS
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
Definition: AnalyzerOptions.h:38
clang::DiagnosticsEngine::Level
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:152
clang::diag::Severity::Ignored
Do not present this diagnostic, ignore it.
clang::diag::kind
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:61
clang::Diagnostic
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1316
clang::diag::Flavor::Remark
A diagnostic that indicates normal progress through compilation.
DiagnosticIDs.h
Defines the Diagnostic IDs-related interfaces.
max
__DEVICE__ int max(int __a, int __b)
Definition: __clang_cuda_device_functions.h:1611
clang::diag::Severity::Fatal
Present this diagnostic as a fatal error.
clang::DiagnosticMapping::setNoWarningAsError
void setNoWarningAsError(bool Value)
Definition: DiagnosticIDs.h:132
clang::DiagnosticIDs::Error
Definition: DiagnosticIDs.h:168
clang::diag::Severity::Warning
Present this diagnostic as a warning.
clang::diag::DIAG_START_COMMON
Definition: DiagnosticIDs.h:46
clang::DiagnosticMapping::hasNoWarningAsError
bool hasNoWarningAsError() const
Definition: DiagnosticIDs.h:131