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/Support/ErrorHandling.h"

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

21#include

22#include

23using namespace clang;

24

25

26

27

28

29namespace {

30

31struct StaticDiagInfoRec;

32

33

34

35

36struct StaticDiagInfoDescriptionStringTable {

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

38 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

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

41#undef DIAG

42};

43

44const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {

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

46 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

47 DESC,

49#undef DIAG

50};

51

52extern const StaticDiagInfoRec StaticDiagInfo[];

53

54

55

56const uint32_t StaticDiagInfoDescriptionOffsets[] = {

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

58 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

59 offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),

61#undef DIAG

62};

63

64

65enum DiagnosticClass {

66 CLASS_NOTE = 0x01,

67 CLASS_REMARK = 0x02,

68 CLASS_WARNING = 0x03,

69 CLASS_EXTENSION = 0x04,

70 CLASS_ERROR = 0x05

71};

72

73struct StaticDiagInfoRec {

74 uint16_t DiagID;

76 uint8_t DefaultSeverity : 3;

77 LLVM_PREFERRED_TYPE(DiagnosticClass)

78 uint8_t Class : 3;

80 uint8_t SFINAE : 2;

82 LLVM_PREFERRED_TYPE(bool)

83 uint8_t WarnNoWerror : 1;

84 LLVM_PREFERRED_TYPE(bool)

85 uint8_t WarnShowInSystemHeader : 1;

86 LLVM_PREFERRED_TYPE(bool)

87 uint8_t WarnShowInSystemMacro : 1;

88

89 uint16_t OptionGroupIndex : 15;

90 LLVM_PREFERRED_TYPE(bool)

91 uint16_t Deferrable : 1;

92

93 uint16_t DescriptionLen;

94

95 unsigned getOptionGroupIndex() const {

96 return OptionGroupIndex;

97 }

98

99 StringRef getDescription() const {

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

101 uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];

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

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

104 }

105

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

108 : diag::Flavor::WarningOrError;

109 }

110

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

112 return DiagID < RHS.DiagID;

113 }

114};

115

116#define STRINGIFY_NAME(NAME) #NAME

117#define VALIDATE_DIAG_SIZE(NAME) \

118 static_assert( \

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

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

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

122 STRINGIFY_NAME( \

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

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

125 "DiagnosticIDs.h.");

139#undef VALIDATE_DIAG_SIZE

140#undef STRINGIFY_NAME

141

142const StaticDiagInfoRec StaticDiagInfo[] = {

143

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

145 SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \

146 { \

147 diag::ENUM, \

148 DEFAULT_SEVERITY, \

149 CLASS, \

150 DiagnosticIDs::SFINAE, \

151 CATEGORY, \

152 NOWERROR, \

153 SHOWINSYSHEADER, \

154 SHOWINSYSMACRO, \

155 GROUP, \

156 DEFERRABLE, \

157 STR_SIZE(DESC, uint16_t)},

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

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

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

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

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

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

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

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

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

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

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

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

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

171

172#undef DIAG

173};

174

175}

176

178

179

180

181static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {

182

183 using namespace diag;

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

185 return nullptr;

186

187

188

189

190

191

192

193

194

195 unsigned Offset = 0;

196 unsigned ID = DiagID - DIAG_START_COMMON - 1;

197#define CATEGORY(NAME, PREV) \

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

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

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

201 }

204CATEGORY(SERIALIZATION, FRONTEND)

212CATEGORY(REFACTORING, ANALYSIS)

213CATEGORY(INSTALLAPI, REFACTORING)

214#undef CATEGORY

215

216

218 return nullptr;

219

221

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

223

224

225

226 if (Found->DiagID != DiagID)

227 return nullptr;

229}

230

234

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

237

238 if (StaticInfo->WarnNoWerror) {

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

242 }

243 }

244

245 return Info;

246}

247

248

249

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

252 return Info->Category;

253 return 0;

254}

255

256namespace {

257

258 struct StaticDiagCategoryRec {

259 const char *NameStr;

261

262 StringRef getName() const {

263 return StringRef(NameStr, NameLen);

264 }

265 };

266}

267

269#define GET_CATEGORY_TABLE

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

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

272#undef GET_CATEGORY_TABLE

273 { nullptr, 0 }

274};

275

276

279}

280

281

282

283

286 return StringRef();

288}

289

290

291

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

297}

298

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

301 return Info->Deferrable;

302 return false;

303}

304

305

306

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

309 return Info->Class;

310 return ~0U;

311}

312

313

314

315

316

318 namespace diag {

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

321 std::vector DiagInfo;

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

323 public:

324

325

326

329 "Invalid diagnostic ID");

331 }

332

333

336 "Invalid diagnostic ID");

338 }

339

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

343

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

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

346 return I->second;

347

348

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

351 DiagInfo.push_back(D);

352 return ID;

353 }

354 };

355

356 }

357}

358

359

360

361

362

363

365

367

368

369

370

371

372

373

375 if (!CustomDiagInfo)

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

378}

379

380

381

382

383

384

388}

389

390

391

395}

396

397

398

399

400

401

403 bool &EnabledByDefault) {

406 return false;

407

408 EnabledByDefault =

410 return true;

411}

412

415 return false;

416

418}

419

420

421

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

424 return Info->getDescription();

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

426 return CustomDiagInfo->getDescription(DiagID);

427}

428

430 switch (SV) {

441 }

442 llvm_unreachable("unexpected severity");

443}

444

445

446

447

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

451

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

454 return CustomDiagInfo->getLevel(DiagID);

455 }

456

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

460}

461

462

463

464

465

466

467

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

472

473

474

476

477

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

480

481

484

485

489

490

491

492

493 bool EnabledByDefault = false;

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

497

498

499

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

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

502

503

506

507

508

509

510

511

512 if (State->IgnoreAllWarnings) {

517 }

518

519

523 }

524

525

526

530 }

531

532

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

536

537

538

539 if (Diag.hasSourceManager())

541

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

543

544 bool ShowInSystemHeader =

546

547

548

549

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

551 SM.isInSystemHeader(SM.getExpansionLoc(Loc)))

553

554

555 bool ShowInSystemMacro =

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

558 SM.isInSystemMacro(Loc))

560

561

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

564

566}

567

568#define GET_DIAG_ARRAYS

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

570#undef GET_DIAG_ARRAYS

571

572namespace {

573 struct WarningOption {

574 uint16_t NameOffset;

575 uint16_t Members;

576 uint16_t SubGroups;

577 StringRef Documentation;

578

579

580 StringRef getName() const {

581 return StringRef(DiagGroupNames + NameOffset + 1,

582 DiagGroupNames[NameOffset]);

583 }

584 };

585}

586

587

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

590 {FlagNameOffset, Members, SubGroups, Docs},

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

592#undef DIAG_ENTRY

593};

594

595

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

598}

599

602}

603

604std::optionaldiag::Group

606 const auto *Found = llvm::partition_point(

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

609 return std::nullopt;

611}

612

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

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

616 return std::nullopt;

617}

618

619

620

621

625 return StringRef();

626}

627

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

630 for (size_t I = 1; DiagGroupNames[I] != '\0';) {

631 std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);

632 I += DiagGroupNames[I] + 1;

633 Res.push_back("-W" + Diag);

634 Res.push_back("-Wno-" + Diag);

635 }

636

637 return Res;

638}

639

640

641

643 const WarningOption *Group,

645

646

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

649

651

652

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

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

657 Diags.push_back(*Member);

658 }

659 }

660

661

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

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

665 Diags);

666

668}

669

670bool

674 return ::getDiagnosticsInGroup(

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

676 return true;

677}

678

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

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

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

684}

685

687 StringRef Group) {

688 StringRef Best;

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

690 for (const WarningOption &O : OptionTable) {

691

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

693 continue;

694

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

696 if (Distance > BestDistance)

697 continue;

698

699

702 continue;

703

704 if (Distance == BestDistance) {

705

706 Best = "";

707 } else if (Distance < BestDistance) {

708

709 Best = O.getName();

710 BestDistance = Distance;

711 }

712 }

713

714 return Best;

715}

716

717

718

722

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

724

725

726 unsigned DiagID = Info.getID();

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

729

730

731

733 ++Diag.TrapNumErrorsOccurred;

734 if (isUnrecoverable(DiagID))

735 ++Diag.TrapNumUnrecoverableErrorsOccurred;

736 }

737

738 if (Diag.SuppressAllDiagnostics)

739 return false;

740

742

743

744

745

747 Diag.FatalErrorOccurred = true;

748

749 Diag.LastDiagLevel = DiagLevel;

750 }

751

752

753

754 if (Diag.FatalErrorOccurred) {

756 Diag.Client->IncludeInDiagnosticCounts()) {

757 ++Diag.NumErrors;

758 }

759

760 return false;

761 }

762

763

764

768 return false;

769

771 if (isUnrecoverable(DiagID))

772 Diag.UnrecoverableErrorOccurred = true;

773

774

776 Diag.UncompilableErrorOccurred = true;

777

778 Diag.ErrorOccurred = true;

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

780 ++Diag.NumErrors;

781 }

782

783

784

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

787 Diag.Report(diag::fatal_too_many_errors);

788 return false;

789 }

790 }

791

792

793

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

795 Diag.FatalErrorOccurred = true;

796

797 EmitDiag(Diag, DiagBuilder, DiagLevel);

798 return true;

799}

800

803 Level DiagLevel) const {

806

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

810 ++Diag.NumWarnings;

811 }

812}

813

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

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

817

819 }

820

821

823 return false;

824

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

826 DiagID == diag::err_unavailable_message)

827 return false;

828

829

831 return false;

832

834 return false;

835

836 return true;

837}

838

842}

843

847}

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.