Coverage Report

Created: 2024-01-17 10:31

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