clang: lib/Basic/DiagnosticIDs.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

17#include "llvm/ADT/STLExtras.h"

18#include "llvm/ADT/SmallVector.h"

19#include "llvm/ADT/StringTable.h"

20#include "llvm/Support/ErrorHandling.h"

21#include "llvm/Support/Path.h"

22#include

23#include

24using namespace clang;

25

26

27

28

29

30namespace {

31

32struct StaticDiagInfoRec;

33

34

35

36

37struct StaticDiagInfoDescriptionStringTable {

38#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \

39 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

40 char ENUM##_desc[sizeof(DESC)];

42#undef DIAG

43};

44

45const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {

46#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \

47 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

48 DESC,

50#undef DIAG

51};

52

53extern const StaticDiagInfoRec StaticDiagInfo[];

54

55

56

57const uint32_t StaticDiagInfoDescriptionOffsets[] = {

58#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \

59 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

60 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),

62#undef DIAG

63};

64

65

66enum DiagnosticClass {

67 CLASS_NOTE = 0x01,

68 CLASS_REMARK = 0x02,

69 CLASS_WARNING = 0x03,

70 CLASS_EXTENSION = 0x04,

71 CLASS_ERROR = 0x05

72};

73

74struct StaticDiagInfoRec {

75 uint16_t DiagID;

77 uint8_t DefaultSeverity : 3;

78 LLVM_PREFERRED_TYPE(DiagnosticClass)

79 uint8_t Class : 3;

81 uint8_t SFINAE : 2;

83 LLVM_PREFERRED_TYPE(bool)

84 uint8_t WarnNoWerror : 1;

85 LLVM_PREFERRED_TYPE(bool)

86 uint8_t WarnShowInSystemHeader : 1;

87 LLVM_PREFERRED_TYPE(bool)

88 uint8_t WarnShowInSystemMacro : 1;

89

90 uint16_t OptionGroupIndex : 15;

91 LLVM_PREFERRED_TYPE(bool)

92 uint16_t Deferrable : 1;

93

94 uint16_t DescriptionLen;

95

96 unsigned getOptionGroupIndex() const {

97 return OptionGroupIndex;

98 }

99

100 StringRef getDescription() const {

101 size_t MyIndex = this - &StaticDiagInfo[0];

102 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];

103 const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);

104 return StringRef(&Table[StringOffset], DescriptionLen);

105 }

106

108 return Class == CLASS_REMARK ? diag::Flavor::Remark

109 : diag::Flavor::WarningOrError;

110 }

111

112 bool operator<(const StaticDiagInfoRec &RHS) const {

113 return DiagID < RHS.DiagID;

114 }

115};

116

117#define STRINGIFY_NAME(NAME) #NAME

118#define VALIDATE_DIAG_SIZE(NAME) \

119 static_assert( \

120 static_cast(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \

121 static_cast(diag::DIAG_START_##NAME) + \

122 static_cast(diag::DIAG_SIZE_##NAME), \

123 STRINGIFY_NAME( \

124 DIAG_SIZE_##NAME) " is insufficient to contain all " \

125 "diagnostics, it may need to be made larger in " \

126 "DiagnosticIDs.h.");

140#undef VALIDATE_DIAG_SIZE

141#undef STRINGIFY_NAME

142

143const StaticDiagInfoRec StaticDiagInfo[] = {

144

145#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \

146 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

147 { \

148 diag::ENUM, \

149 DEFAULT_SEVERITY, \

150 CLASS, \

151 DiagnosticIDs::SFINAE, \

152 CATEGORY, \

153 NOWERROR, \

154 SHOWINSYSHEADER, \

155 SHOWINSYSMACRO, \

156 GROUP, \

157 DEFERRABLE, \

158 STR_SIZE(DESC, uint16_t)},

159#include "clang/Basic/DiagnosticCommonKinds.inc"

160#include "clang/Basic/DiagnosticDriverKinds.inc"

161#include "clang/Basic/DiagnosticFrontendKinds.inc"

162#include "clang/Basic/DiagnosticSerializationKinds.inc"

163#include "clang/Basic/DiagnosticLexKinds.inc"

164#include "clang/Basic/DiagnosticParseKinds.inc"

165#include "clang/Basic/DiagnosticASTKinds.inc"

166#include "clang/Basic/DiagnosticCommentKinds.inc"

167#include "clang/Basic/DiagnosticCrossTUKinds.inc"

168#include "clang/Basic/DiagnosticSemaKinds.inc"

169#include "clang/Basic/DiagnosticAnalysisKinds.inc"

170#include "clang/Basic/DiagnosticRefactoringKinds.inc"

171#include "clang/Basic/DiagnosticInstallAPIKinds.inc"

172

173#undef DIAG

174};

175

176}

177

179

180

181

182static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {

183

184 using namespace diag;

185 if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)

186 return nullptr;

187

188

189

190

191

192

193

194

195

196 unsigned Offset = 0;

197 unsigned ID = DiagID - DIAG_START_COMMON - 1;

198#define CATEGORY(NAME, PREV) \

199 if (DiagID > DIAG_START_##NAME) { \

200 Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \

201 ID -= DIAG_START_##NAME - DIAG_START_##PREV; \

202 }

205CATEGORY(SERIALIZATION, FRONTEND)

213CATEGORY(REFACTORING, ANALYSIS)

214CATEGORY(INSTALLAPI, REFACTORING)

215#undef CATEGORY

216

217

219 return nullptr;

220

222

223 const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];

224

225

226

227 if (Found->DiagID != DiagID)

228 return nullptr;

230}

231

235

236 if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {

238

239 if (StaticInfo->WarnNoWerror) {

241 "Unexpected mapping with no-Werror bit!");

243 }

244 }

245

246 return Info;

247}

248

249

250

252 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

253 return Info->Category;

254 return 0;

255}

256

257namespace {

258

259 struct StaticDiagCategoryRec {

260 const char *NameStr;

262

263 StringRef getName() const {

264 return StringRef(NameStr, NameLen);

265 }

266 };

267}

268

270#define GET_CATEGORY_TABLE

271#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },

272#include "clang/Basic/DiagnosticGroups.inc"

273#undef GET_CATEGORY_TABLE

274 { nullptr, 0 }

275};

276

277

280}

281

282

283

284

287 return StringRef();

289}

290

291

292

295 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

298}

299

301 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

302 return Info->Deferrable;

303 return false;

304}

305

306

307

309 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

310 return Info->Class;

311 return ~0U;

312}

313

314

315

316

317

319 namespace diag {

321 typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;

322 std::vector DiagInfo;

323 std::map<DiagDesc, unsigned> DiagIDs;

324 public:

325

326

327

330 "Invalid diagnostic ID");

332 }

333

334

337 "Invalid diagnostic ID");

339 }

340

343 DiagDesc D(L, std::string(Message));

344

345 std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);

346 if (I != DiagIDs.end() && I->first == D)

347 return I->second;

348

349

351 DiagIDs.insert(std::make_pair(D, ID));

352 DiagInfo.push_back(D);

353 return ID;

354 }

355 };

356

357 }

358}

359

360

361

362

363

364

366

368

369

370

371

372

373

374

376 if (!CustomDiagInfo)

378 return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);

379}

380

381

382

383

384

385

389}

390

391

392

396}

397

398

399

400

401

402

404 bool &EnabledByDefault) {

407 return false;

408

409 EnabledByDefault =

411 return true;

412}

413

416 return false;

417

419}

420

421

422

424 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

425 return Info->getDescription();

426 assert(CustomDiagInfo && "Invalid CustomDiagInfo");

427 return CustomDiagInfo->getDescription(DiagID);

428}

429

431 switch (SV) {

442 }

443 llvm_unreachable("unexpected severity");

444}

445

446

447

448

450DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,

452

454 assert(CustomDiagInfo && "Invalid CustomDiagInfo");

455 return CustomDiagInfo->getLevel(DiagID);

456 }

457

460 return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));

461}

462

463

464

465

466

467

468

470DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,

473

474

475

477

478

479 DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);

481

482

485

486

490

491

492

493

494 bool EnabledByDefault = false;

496 if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)

498

499

500

501 if (IsExtensionDiag && !Mapping.isUser())

502 Result = std::max(Result, State->ExtBehavior);

503

504

507

508

509

510

511

512

513 if (State->IgnoreAllWarnings) {

518 }

519

520

524 }

525

526

527

531 }

532

533

535 DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)

537

538

539

540 if (Diag.hasSourceManager())

542

543 const auto &SM = Diag.getSourceManager();

544

545 bool ShowInSystemHeader =

547

548

549

550

551 if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&

552 SM.isInSystemHeader(SM.getExpansionLoc(Loc)))

554

555

556 bool ShowInSystemMacro =

558 if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&

559 SM.isInSystemMacro(Loc))

561

562

563 if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc))

565

567}

568

569#define GET_DIAG_ARRAYS

570#include "clang/Basic/DiagnosticGroups.inc"

571#undef GET_DIAG_ARRAYS

572

573namespace {

574 struct WarningOption {

575 uint16_t NameOffset;

576 uint16_t Members;

577 uint16_t SubGroups;

578 StringRef Documentation;

579

580 StringRef getName() const { return DiagGroupNames[NameOffset]; }

581 };

582}

583

584

586#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \

587 {FlagNameOffset, Members, SubGroups, Docs},

588#include "clang/Basic/DiagnosticGroups.inc"

589#undef DIAG_ENTRY

590};

591

592

594 return OptionTable[static_cast<int>(Group)].Documentation;

595}

596

599}

600

601std::optionaldiag::Group

603 const auto *Found = llvm::partition_point(

604 OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });

606 return std::nullopt;

608}

609

611 if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))

612 return static_cast<diag::Group>(Info->getOptionGroupIndex());

613 return std::nullopt;

614}

615

616

617

618

622 return StringRef();

623}

624

626 std::vectorstd::string Res{"-W", "-Wno-"};

627 for (StringRef Name : DiagGroupNames) {

628 if (Name.empty())

629 continue;

630

631 Res.push_back((Twine("-W") + Name).str());

632 Res.push_back((Twine("-Wno-") + Name).str());

633 }

634

635 return Res;

636}

637

638

639

641 const WarningOption *Group,

643

644

645 if (!Group->Members && !Group->SubGroups)

647

649

650

651 const int16_t *Member = DiagArrays + Group->Members;

653 if (GetDiagInfo(*Member)->getFlavor() == Flavor) {

655 Diags.push_back(*Member);

656 }

657 }

658

659

660 const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;

661 for (; *SubGroups != (int16_t)-1; ++SubGroups)

663 Diags);

664

666}

667

668bool

672 return ::getDiagnosticsInGroup(

673 Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);

674 return true;

675}

676

678 std::vectordiag::kind &Diags) {

680 if (StaticDiagInfo[i].getFlavor() == Flavor)

681 Diags.push_back(StaticDiagInfo[i].DiagID);

682}

683

685 StringRef Group) {

686 StringRef Best;

687 unsigned BestDistance = Group.size() + 1;

688 for (const WarningOption &O : OptionTable) {

689

690 if (!O.Members && !O.SubGroups)

691 continue;

692

693 unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);

694 if (Distance > BestDistance)

695 continue;

696

697

700 continue;

701

702 if (Distance == BestDistance) {

703

704 Best = "";

705 } else if (Distance < BestDistance) {

706

707 Best = O.getName();

708 BestDistance = Distance;

709 }

710 }

711

712 return Best;

713}

714

715

716

720

721 assert(Diag.getClient() && "DiagnosticClient not set!");

722

723

724 unsigned DiagID = Info.getID();

726 = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);

727

728

729

731 ++Diag.TrapNumErrorsOccurred;

732 if (isUnrecoverable(DiagID))

733 ++Diag.TrapNumUnrecoverableErrorsOccurred;

734 }

735

736 if (Diag.SuppressAllDiagnostics)

737 return false;

738

740

741

742

743

745 Diag.FatalErrorOccurred = true;

746

747 Diag.LastDiagLevel = DiagLevel;

748 }

749

750

751

752 if (Diag.FatalErrorOccurred) {

754 Diag.Client->IncludeInDiagnosticCounts()) {

755 ++Diag.NumErrors;

756 }

757

758 return false;

759 }

760

761

762

766 return false;

767

769 if (isUnrecoverable(DiagID))

770 Diag.UnrecoverableErrorOccurred = true;

771

772

774 Diag.UncompilableErrorOccurred = true;

775

776 Diag.ErrorOccurred = true;

777 if (Diag.Client->IncludeInDiagnosticCounts()) {

778 ++Diag.NumErrors;

779 }

780

781

782

783 if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&

785 Diag.Report(diag::fatal_too_many_errors);

786 return false;

787 }

788 }

789

790

791

792 if (Info.getID() == diag::fatal_too_many_errors)

793 Diag.FatalErrorOccurred = true;

794

795 EmitDiag(Diag, DiagBuilder, DiagLevel);

796 return true;

797}

798

801 Level DiagLevel) const {

804

806 if (Diag.Client->IncludeInDiagnosticCounts()) {

808 ++Diag.NumWarnings;

809 }

810}

811

812bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {

814 assert(CustomDiagInfo && "Invalid CustomDiagInfo");

815

817 }

818

819

821 return false;

822

823 if (DiagID == diag::err_unavailable ||

824 DiagID == diag::err_unavailable_message)

825 return false;

826

827

829 return false;

830

832 return false;

833

834 return true;

835}

836

840}

841

845}

Includes all the separate Diagnostic headers & some related helpers.

static const StaticDiagInfoRec * GetDiagInfo(unsigned DiagID)

GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, or null if the ID is inval...

static DiagnosticIDs::Level toLevel(diag::Severity SV)

#define VALIDATE_DIAG_SIZE(NAME)

#define CATEGORY(NAME, PREV)

static const unsigned StaticDiagInfoSize

static unsigned getBuiltinDiagClass(unsigned DiagID)

getBuiltinDiagClass - Return the class field of the diagnostic.

static const WarningOption OptionTable[]

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...

static const StaticDiagCategoryRec CategoryNameTable[]

Defines the Diagnostic IDs-related interfaces.

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.

static std::string getName(const CallEvent &Call)

Defines the SourceManager interface.

A little helper class used to produce diagnostics.

Used for handling and querying diagnostic IDs.

static bool isBuiltinExtensionDiag(unsigned DiagID)

Determine whether the given built-in diagnostic ID is for an extension of some sort.

static StringRef getCategoryNameFromID(unsigned CategoryID)

Given a category ID, return the name of the category.

static unsigned getNumberOfCategories()

Return the number of diagnostic categories.

static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group)

Get the diagnostic option with the closest edit distance to the given group name.

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.

static std::vector< std::string > getDiagnosticFlags()

Get the string of all diagnostic flags.

static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID)

Determines whether the given built-in diagnostic ID is for an error that is suppressed if it occurs d...

static bool isDefaultMappingAsError(unsigned DiagID)

Return true if the specified diagnostic is mapped to errors by default.

static bool isBuiltinNote(unsigned DiagID)

Determine whether the given built-in diagnostic ID is a Note.

static bool isBuiltinWarningOrExtension(unsigned DiagID)

Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension.

static bool isCodegenABICheckDiagnostic(unsigned DiagID)

Return true if a given diagnostic is a codegen-time ABI check.

StringRef getDescription(unsigned DiagID) const

Given a diagnostic ID, return a description of the issue.

SFINAEResponse

Enumeration describing how the emission of a diagnostic should be treated when it occurs during C++ t...

@ SFINAE_Report

The diagnostic should be reported.

static StringRef getWarningOptionForDiag(unsigned DiagID)

Return the lowest-level warning option that enables the specified diagnostic.

static StringRef getWarningOptionDocumentation(diag::Group GroupID)

Given a diagnostic group ID, return its documentation.

static std::optional< diag::Group > getGroupForWarningOption(StringRef)

Given a group ID, returns the flag that toggles the group.

static unsigned getCategoryNumberForDiag(unsigned DiagID)

Return the category number that a specified DiagID belongs to, or 0 if no category.

static std::optional< diag::Group > getGroupForDiag(unsigned DiagID)

Return the lowest-level group that contains the specified diagnostic.

static StringRef getWarningOptionForGroup(diag::Group)

Given a group ID, returns the flag that toggles the group.

static bool isARCDiagnostic(unsigned DiagID)

Return true if a given diagnostic falls into an ARC diagnostic category.

Level

The level of the diagnostic, after it has been through mapping.

static void getAllDiagnostics(diag::Flavor Flavor, std::vector< diag::kind > &Diags)

Get the set of all diagnostic IDs.

static DiagnosticMapping getDefaultMapping(unsigned DiagID)

Get the default mapping for this diagnostic.

unsigned getCustomDiagID(Level L, StringRef FormatString)

Return an ID for a diagnostic with the specified format string and level.

static bool isDeferrable(unsigned DiagID)

Whether the diagnostic message can be deferred.

bool hasNoErrorAsFatal() const

void setNoWarningAsError(bool Value)

void setSeverity(diag::Severity Value)

diag::Severity getSeverity() const

static DiagnosticMapping Make(diag::Severity Severity, bool IsUser, bool IsPragma)

bool hasNoWarningAsError() const

A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...

Concrete class used by the front-end to report problems and issues.

Level

The level of the diagnostic, after it has been through mapping.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

StringRef getDescription(unsigned DiagID) const

getDescription - Return the description of the specified custom diagnostic.

unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, DiagnosticIDs &Diags)

DiagnosticIDs::Level getLevel(unsigned DiagID) const

getLevel - Return the level of the specified custom diagnostic.

Severity

Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...

@ Warning

Present this diagnostic as a warning.

@ Fatal

Present this diagnostic as a fatal error.

@ Error

Present this diagnostic as an error.

@ Remark

Present this diagnostic as a remark.

@ Ignored

Do not present this diagnostic, ignore it.

Flavor

Flavors of diagnostics we can emit.

@ Remark

A diagnostic that indicates normal progress through compilation.

The JSON file list parser is used to communicate input to InstallAPI.

bool operator<(DeclarationName LHS, DeclarationName RHS)

Ordering on two declaration names.

@ Result

The result type of a method or function.

@ Class

The "class" keyword introduces the elaborated-type-specifier.