cjdb created this revision. cjdb added reviewers: dblaikie, erichkeane. Herald added subscribers: kadircet, arphaman. Herald added a project: All. cjdb requested review of this revision. Herald added projects: clang, libc++abi, clang-tools-extra. Herald added subscribers: cfe-commits, libcxx-commits. Herald added a reviewer: libc++abi.
Structured diagnostics enable us to have diagnostics that contain a headline description and a detailed description. DiagReason represents the latter, although some subengines might combine the two into a single message. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140125 Files: clang-tools-extra/clangd/Diagnostics.cpp clang/include/clang/Basic/Diagnostic.h clang/include/clang/Basic/Diagnostic.td clang/include/clang/Basic/DiagnosticAST.h clang/include/clang/Basic/DiagnosticAnalysis.h clang/include/clang/Basic/DiagnosticComment.h clang/include/clang/Basic/DiagnosticCrossTU.h clang/include/clang/Basic/DiagnosticDriver.h clang/include/clang/Basic/DiagnosticFrontend.h clang/include/clang/Basic/DiagnosticIDs.h clang/include/clang/Basic/DiagnosticLex.h clang/include/clang/Basic/DiagnosticParse.h clang/include/clang/Basic/DiagnosticRefactoring.h clang/include/clang/Basic/DiagnosticSema.h clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/DiagnosticSerialization.h clang/include/clang/Frontend/ASTUnit.h clang/lib/Basic/Diagnostic.cpp clang/lib/Basic/DiagnosticIDs.cpp clang/lib/Frontend/ASTUnit.cpp clang/test/TableGen/DiagnosticBase.inc clang/test/TableGen/deferred-diag.td clang/tools/diagtool/DiagnosticNames.cpp clang/utils/TableGen/ClangDiagnosticsEmitter.cpp libcxxabi/test/test_demangle.pass.cpp
Index: clang/utils/TableGen/ClangDiagnosticsEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -604,7 +604,7 @@ std::vector<std::string> buildForDocumentation(StringRef Role, const Record *R); - std::string buildForDefinition(const Record *R); + std::string buildForDefinition(const Record *R, StringRef Field); Piece *getSubstitution(SubstitutionPiece *S) const { auto It = Substitutions.find(S->Name); @@ -1182,9 +1182,10 @@ return Result; } -std::string DiagnosticTextBuilder::buildForDefinition(const Record *R) { +std::string DiagnosticTextBuilder::buildForDefinition(const Record *R, + StringRef Field) { EvaluatingRecordGuard Guard(&EvaluatingRecord, R); - StringRef Text = R->getValueAsString("Summary"); + StringRef Text = R->getValueAsString(Field); DiagText D(*this, Text); std::string Result; DiagTextPrinter{*this, Result}.Visit(D.Root); @@ -1276,7 +1277,7 @@ // Description string. OS << ", \""; - OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; + OS.write_escaped(DiagTextBuilder.buildForDefinition(&R, "Summary")) << '"'; // Warning group associated with the diagnostic. This is stored as an index // into the alphabetically sorted warning group table. @@ -1320,6 +1321,12 @@ // Category number. OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); + + // Reasons + OS << ", /*Reason=*/\""; + OS.write_escaped(DiagTextBuilder.buildForDefinition( + R.getValueAsDef("Reason"), "Value")) + << '"'; OS << ")\n"; } } Index: clang/tools/diagtool/DiagnosticNames.cpp =================================================================== --- clang/tools/diagtool/DiagnosticNames.cpp +++ clang/tools/diagtool/DiagnosticNames.cpp @@ -28,7 +28,7 @@ // out of sync easily? static const DiagnosticRecord BuiltinDiagnosticsByID[] = { #define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFER, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFER, CATEGORY, REASON) \ {#ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t)}, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticCrossTUKinds.inc" Index: clang/test/TableGen/deferred-diag.td =================================================================== --- clang/test/TableGen/deferred-diag.td +++ clang/test/TableGen/deferred-diag.td @@ -5,23 +5,23 @@ // Test usage of Deferrable and NonDeferrable in diagnostics. def test_default : Error<"This error is non-deferrable by default">; -// CHECK-DAG: DIAG(test_default, {{.*}}SFINAE_SubstitutionFailure, false, true, true, false, 0) +// CHECK-DAG: DIAG(test_default, {{.*}}SFINAE_SubstitutionFailure, false, true, true, false, 0, /*Reason=*/"") def test_deferrable : Error<"This error is deferrable">, Deferrable; -// CHECK-DAG: DIAG(test_deferrable, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0) +// CHECK-DAG: DIAG(test_deferrable, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0, /*Reason=*/"") def test_non_deferrable : Error<"This error is non-deferrable">, NonDeferrable; -// CHECK-DAG: DIAG(test_non_deferrable, {{.*}} SFINAE_SubstitutionFailure, false, true, true, false, 0) +// CHECK-DAG: DIAG(test_non_deferrable, {{.*}} SFINAE_SubstitutionFailure, false, true, true, false, 0, /*Reason=*/"") let Deferrable = 1 in { def test_let : Error<"This error is deferrable by let">; -// CHECK-DAG: DIAG(test_let, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0) +// CHECK-DAG: DIAG(test_let, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0, /*Reason=*/"") // Make sure TextSubstitution is allowed in the let Deferrable block. def textsub : TextSubstitution<"%select{text1|text2}0">; def test_let2 : Error<"This error is deferrable by let %sub{textsub}0">; -// CHECK-DAG: DIAG(test_let2, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0) +// CHECK-DAG: DIAG(test_let2, {{.*}} SFINAE_SubstitutionFailure, false, true, true, true, 0, /*Reason=*/"") } Index: clang/test/TableGen/DiagnosticBase.inc =================================================================== --- clang/test/TableGen/DiagnosticBase.inc +++ clang/test/TableGen/DiagnosticBase.inc @@ -64,10 +64,17 @@ class InGroup<DiagGroup G> { DiagGroup Group = G; } //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } +// Structured diagnostics enable us to have diagnostics that contain a headline +// description and a detailed description. DiagReason represents the latter, +// although some subengines might combine the two into a single message. +class DiagReason<string value> { + string Value = value; +} +def NO_REASON_YET : DiagReason<"">; include "DiagnosticDocs.inc" // All diagnostics emitted by the compiler are an indirect subclass of this. -class Diagnostic<string summary, DiagClass DC, Severity defaultmapping> { +class Diagnostic<string summary, DiagClass DC, Severity defaultmapping, DiagReason reason> { /// Component is specified by the file with a big let directive. string Component = ?; string Summary = summary; @@ -81,6 +88,7 @@ Severity DefaultSeverity = defaultmapping; DiagGroup Group; string CategoryName = ""; + DiagReason Reason = reason; } class SFINAEFailure { @@ -118,24 +126,24 @@ } // FIXME: ExtWarn and Extension should also be SFINAEFailure by default. -class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure { +class Error<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_ERROR, SEV_Error, reason>, SFINAEFailure { bit ShowInSystemHeader = 1; } // Warnings default to on (but can be default-off'd with DefaultIgnore). // This is used for warnings about questionable code; warnings about // accepted language extensions should use Extension or ExtWarn below instead. -class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>; +class Warning<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_WARNING, SEV_Warning, reason>; // Remarks can be turned on with -R flags and provide commentary, e.g. on // optimizer decisions. -class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>; +class Remark<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_REMARK, SEV_Ignored, reason>; // Extensions are warnings about accepted language extensions. // Extension warnings are default-off but enabled by -pedantic. -class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>; +class Extension<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored, reason>; // ExtWarns are warnings about accepted language extensions. // ExtWarn warnings are default-on. -class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>; +class ExtWarn<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning, reason>; // Notes can provide supplementary information on errors, warnings, and remarks. -class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>; +class Note<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/, reason>; class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; } Index: clang/lib/Frontend/ASTUnit.cpp =================================================================== --- clang/lib/Frontend/ASTUnit.cpp +++ clang/lib/Frontend/ASTUnit.cpp @@ -2382,8 +2382,8 @@ FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); } - Result.push_back(StoredDiagnostic(SD.Level, SD.ID, - SD.Message, Loc, Ranges, FixIts)); + Result.push_back(StoredDiagnostic(SD.Level, SD.ID, SD.Message, SD.Reason, + Loc, Ranges, FixIts)); } Result.swap(Out); } Index: clang/lib/Basic/DiagnosticIDs.cpp =================================================================== --- clang/lib/Basic/DiagnosticIDs.cpp +++ clang/lib/Basic/DiagnosticIDs.cpp @@ -33,7 +33,7 @@ // platforms. See "How To Write Shared Libraries" by Ulrich Drepper. struct StaticDiagInfoDescriptionStringTable { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ char ENUM##_desc[sizeof(DESC)]; // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -54,7 +54,8 @@ const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + REASON) \ DESC, // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -69,7 +70,7 @@ #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" #include "clang/Basic/DiagnosticRefactoringKinds.inc" - // clang-format on +// clang-format on #undef DIAG }; @@ -79,7 +80,8 @@ // StaticDiagInfoRec would have extra padding on 64-bit platforms. const uint32_t StaticDiagInfoDescriptionOffsets[] = { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + REASON) \ offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc), // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -93,11 +95,81 @@ #include "clang/Basic/DiagnosticCrossTUKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +// clang-format on +#undef DIAG +}; + +// Reason.Legacy +struct StaticDiagInfoReasonStringTable { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + REASON) \ + char ENUM##_reason[sizeof(REASON)]; + // clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" #include "clang/Basic/DiagnosticRefactoringKinds.inc" // clang-format on #undef DIAG }; +const StaticDiagInfoReasonStringTable + StaticDiagInfoReasons = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + REASON) \ + REASON, +// clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +// clang-format on +#undef DIAG +}; + +// Stored separately from StaticDiagInfoRec to pack better. Otherwise, +// StaticDiagInfoRec would have extra padding on 64-bit platforms. +const uint32_t StaticDiagInfoReasonOffsets[] = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + REASON) \ + offsetof(StaticDiagInfoReasonStringTable, ENUM##_reason), +// clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +// clang-format on +#undef DIAG +}; + // Diagnostic classes. enum { CLASS_NOTE = 0x01, @@ -121,6 +193,7 @@ uint16_t Deferrable : 1; uint16_t DescriptionLen; + uint16_t ReasonLen; unsigned getOptionGroupIndex() const { return OptionGroupIndex; @@ -133,6 +206,14 @@ return StringRef(&Table[StringOffset], DescriptionLen); } + StringRef getReason() const { + size_t MyIndex = this - &StaticDiagInfo[0]; + uint32_t StringOffset = StaticDiagInfoReasonOffsets[MyIndex]; + const char *Table = + reinterpret_cast<const char *>(&StaticDiagInfoReasons); + return StringRef(&Table[StringOffset], ReasonLen); + } + diag::Flavor getFlavor() const { return Class == CLASS_REMARK ? diag::Flavor::Remark : diag::Flavor::WarningOrError; @@ -171,7 +252,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = { // clang-format off #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ { \ diag::ENUM, \ DEFAULT_SEVERITY, \ @@ -183,7 +264,8 @@ SHOWINSYSMACRO, \ GROUP, \ DEFERRABLE, \ - STR_SIZE(DESC, uint16_t)}, + STR_SIZE(DESC, uint16_t), \ + STR_SIZE(REASON, uint16_t)}, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -222,22 +304,22 @@ // memory at all. unsigned Offset = 0; unsigned ID = DiagID - DIAG_START_COMMON - 1; -#define CATEGORY(NAME, PREV) \ - if (DiagID > DIAG_START_##NAME) { \ - Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \ - ID -= DIAG_START_##NAME - DIAG_START_##PREV; \ +#define CATEGORY(NAME, PREV) \ + if (DiagID > DIAG_START_##NAME) { \ + Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \ + ID -= DIAG_START_##NAME - DIAG_START_##PREV; \ } -CATEGORY(DRIVER, COMMON) -CATEGORY(FRONTEND, DRIVER) -CATEGORY(SERIALIZATION, FRONTEND) -CATEGORY(LEX, SERIALIZATION) -CATEGORY(PARSE, LEX) -CATEGORY(AST, PARSE) -CATEGORY(COMMENT, AST) -CATEGORY(CROSSTU, COMMENT) -CATEGORY(SEMA, CROSSTU) -CATEGORY(ANALYSIS, SEMA) -CATEGORY(REFACTORING, ANALYSIS) + CATEGORY(DRIVER, COMMON) + CATEGORY(FRONTEND, DRIVER) + CATEGORY(SERIALIZATION, FRONTEND) + CATEGORY(LEX, SERIALIZATION) + CATEGORY(PARSE, LEX) + CATEGORY(AST, PARSE) + CATEGORY(COMMENT, AST) + CATEGORY(CROSSTU, COMMENT) + CATEGORY(SEMA, CROSSTU) + CATEGORY(ANALYSIS, SEMA) + CATEGORY(REFACTORING, ANALYSIS) #undef CATEGORY // Avoid out of bounds reads. @@ -281,15 +363,15 @@ } namespace { - // The diagnostic category names. - struct StaticDiagCategoryRec { - const char *NameStr; - uint8_t NameLen; +// The diagnostic category names. +struct StaticDiagCategoryRec { + const char *NameStr; + uint8_t NameLen; - StringRef getName() const { - return StringRef(NameStr, NameLen); - } - }; + StringRef getName() const { + return StringRef(NameStr, NameLen); + } +}; } // Unfortunately, the split between DiagnosticIDs and Diagnostic is not @@ -325,7 +407,7 @@ /// invalid. StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { if (CategoryID >= getNumberOfCategories()) - return StringRef(); + return StringRef(); return CategoryNameTable[CategoryID].getName(); } @@ -359,29 +441,60 @@ namespace clang { namespace diag { class CustomDiagInfo { - typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc; + struct DiagDesc { + DiagnosticIDs::Level Level; + std::string Message; + DiagnosticReason Reason; + + // FIXME(spaceship): default when C++20 becomes the default + bool operator==(const DiagDesc &Other) const { + return std::tie(Level, Message, Reason) == + std::tie(Other.Level, Other.Message, Other.Reason); + } + + bool operator!=(const DiagDesc &Other) const { return !(*this == Other); } + + bool operator<(const DiagDesc &Other) const { + return std::tie(Level, Message, Reason) < + std::tie(Other.Level, Other.Message, Other.Reason); + } + + bool operator>(const DiagDesc &Other) const { return Other < *this; } + + bool operator<=(const DiagDesc &Other) const { return !(Other < *this); } + + bool operator>=(const DiagDesc &Other) const { return !(*this < Other); } + }; std::vector<DiagDesc> DiagInfo; std::map<DiagDesc, unsigned> DiagIDs; - public: + bool IsValidDiagnosticID(unsigned DiagID) const { + return DiagID - DIAG_UPPER_LIMIT < DiagInfo.size(); + } + + public: /// getDescription - Return the description of the specified custom /// diagnostic. StringRef getDescription(unsigned DiagID) const { - assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() && - "Invalid diagnostic ID"); - return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second; + assert(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Message; + } + + StringRef getReason(unsigned DiagID) const { + assert(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Reason.Value; } /// getLevel - Return the level of the specified custom diagnostic. DiagnosticIDs::Level getLevel(unsigned DiagID) const { - assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() && - "Invalid diagnostic ID"); - return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; + assert(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Level; } unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, + const DiagnosticReason &Reason, DiagnosticIDs &Diags) { - DiagDesc D(L, std::string(Message)); + DiagDesc D{L, std::string(Message), Reason}; // Check to see if it already exists. std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); if (I != DiagIDs.end() && I->first == D) @@ -413,10 +526,11 @@ /// /// \param FormatString A fixed diagnostic format string that will be hashed and /// mapped to a unique DiagID. -unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) { +unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString, + const DiagnosticReason &Reason) { if (!CustomDiagInfo) CustomDiagInfo.reset(new diag::CustomDiagInfo()); - return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this); + return CustomDiagInfo->getOrCreateDiagID(L, FormatString, Reason, *this); } @@ -433,7 +547,7 @@ /// Note. bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) { return DiagID < diag::DIAG_UPPER_LIMIT && - getBuiltinDiagClass(DiagID) == CLASS_NOTE; + getBuiltinDiagClass(DiagID) == CLASS_NOTE; } /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic @@ -442,7 +556,7 @@ /// which case -pedantic enables it) or treated as a warning/error by default. /// bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID, - bool &EnabledByDefault) { + bool &EnabledByDefault) { if (DiagID >= diag::DIAG_UPPER_LIMIT || getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) return false; @@ -468,6 +582,13 @@ return CustomDiagInfo->getDescription(DiagID); } +StringRef DiagnosticIDs::getReason(unsigned DiagID) const { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->getReason(); + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + return CustomDiagInfo->getReason(DiagID); +} + static DiagnosticIDs::Level toLevel(diag::Severity SV) { switch (SV) { case diag::Severity::Ignored: @@ -603,18 +724,18 @@ #undef GET_DIAG_ARRAYS namespace { - struct WarningOption { - uint16_t NameOffset; - uint16_t Members; - uint16_t SubGroups; - StringRef Documentation; - - // String is stored with a pascal-style length byte. - StringRef getName() const { - return StringRef(DiagGroupNames + NameOffset + 1, - DiagGroupNames[NameOffset]); - } - }; +struct WarningOption { + uint16_t NameOffset; + uint16_t Members; + uint16_t SubGroups; + StringRef Documentation; + + // String is stored with a pascal-style length byte. + StringRef getName() const { + return StringRef(DiagGroupNames + NameOffset + 1, + DiagGroupNames[NameOffset]); + } +}; } // Second the table of options, sorted by name for fast binary lookup. @@ -702,7 +823,7 @@ bool DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, - SmallVectorImpl<diag::kind> &Diags) const { + SmallVectorImpl<diag::kind> &Diags) const { if (llvm::Optional<diag::Group> G = getGroupForWarningOption(Group)) return ::getDiagnosticsInGroup( Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags); Index: clang/lib/Basic/Diagnostic.cpp =================================================================== --- clang/lib/Basic/Diagnostic.cpp +++ clang/lib/Basic/Diagnostic.cpp @@ -788,11 +788,7 @@ } } -/// FormatDiagnostic - Format this diagnostic into a string, substituting the -/// formal arguments into the %0 slots. The result is appended onto the Str -/// array. -void Diagnostic:: -FormatDiagnostic(SmallVectorImpl<char> &OutStr) const { +void Diagnostic::FormatSummary(SmallVectorImpl<char> &OutStr) const { if (!StoredDiagMessage.empty()) { OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end()); return; @@ -804,6 +800,20 @@ FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); } +void Diagnostic::FormatReason(SmallVectorImpl<char> &OutStr) const { + StringRef Diag = getDiags()->getDiagnosticIDs()->getReason(getID()); + if (!Diag.empty()) { + StringRef Colon = ": "; + OutStr.append(Colon.begin(), Colon.end()); + FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); + } +} + +void Diagnostic::FormatDiagnostic(SmallVectorImpl<char> &OutStr) const { + FormatSummary(OutStr); + FormatReason(OutStr); +} + /// pushEscapedString - Append Str to the diagnostic buffer, /// escaping non-printable characters and ill-formed code unit sequences. static void pushEscapedString(StringRef Str, SmallVectorImpl<char> &OutStr) { @@ -1154,8 +1164,8 @@ } StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, - StringRef Message) - : ID(ID), Level(Level), Message(Message) {} + StringRef Message, DiagnosticReason Reason) + : ID(ID), Level(Level), Message(Message), Reason(std::move(Reason)) {} StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) @@ -1172,13 +1182,13 @@ } StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, - StringRef Message, FullSourceLoc Loc, + StringRef Message, DiagnosticReason Reason, + FullSourceLoc Loc, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixIts) - : ID(ID), Level(Level), Loc(Loc), Message(Message), - Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end()) -{ -} + : ID(ID), Level(Level), Loc(Loc), Message(Message), Reason(Reason), + Ranges(Ranges.begin(), Ranges.end()), + FixIts(FixIts.begin(), FixIts.end()) {} llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, const StoredDiagnostic &SD) { Index: clang/include/clang/Frontend/ASTUnit.h =================================================================== --- clang/include/clang/Frontend/ASTUnit.h +++ clang/include/clang/Frontend/ASTUnit.h @@ -99,6 +99,7 @@ unsigned ID; DiagnosticsEngine::Level Level; std::string Message; + DiagnosticReason Reason; std::string Filename; unsigned LocOffset; std::vector<std::pair<unsigned, unsigned>> Ranges; Index: clang/include/clang/Basic/DiagnosticSerialization.h =================================================================== --- clang/include/clang/Basic/DiagnosticSerialization.h +++ clang/include/clang/Basic/DiagnosticSerialization.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define SERIALIZATIONSTART #include "clang/Basic/DiagnosticSerializationKinds.inc" Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4503,37 +4503,44 @@ def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; def note_ovl_candidate_incomplete_deduction_pack : Note< - "candidate template ignored: " - "deduced too few arguments for expanded pack %0; no argument for %ordinal1 " - "expanded parameter in deduced argument pack %2">; + "candidate template ignored", + DiagReason<"deduced too few arguments for expanded pack %0; no argument for" + " %ordinal1 expanded parameter in deduced argument pack %2">>; def note_ovl_candidate_inconsistent_deduction : Note< - "candidate template ignored: deduced %select{conflicting types|" - "conflicting values|conflicting templates|packs of different lengths}0 " - "for parameter %1%diff{ ($ vs. $)|}2,3">; + "candidate template ignored", + DiagReason<"deduced %select{conflicting types|conflicting values|" + "conflicting templates|packs of different lengths}0 " + "for parameter %1%diff{ ($ vs. $)|}2,3">>; def note_ovl_candidate_inconsistent_deduction_types : Note< - "candidate template ignored: deduced values %diff{" - "of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|" - "%1 and %3 of conflicting types for parameter %0}2,4">; + "candidate template ignored", + DiagReason<"deduced values %diff{" + "of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|" + "%1 and %3 of conflicting types for parameter %0}2,4">>; def note_ovl_candidate_explicit_arg_mismatch_named : Note< - "candidate template ignored: invalid explicitly-specified argument " - "for template parameter %0">; + "candidate template ignored", + DiagReason<"invalid explicitly-specified argument for template parameter %0">>; def note_ovl_candidate_unsatisfied_constraints : Note< - "candidate template ignored: constraints not satisfied%0">; + "candidate template ignored", + DiagReason<"constraints not satisfied%0">>; def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< - "candidate template ignored: invalid explicitly-specified argument " - "for %ordinal0 template parameter">; + "candidate template ignored", + DiagReason<"invalid explicitly-specified argument for %ordinal0 template " + "parameter">>; def note_ovl_candidate_instantiation_depth : Note< - "candidate template ignored: substitution exceeded maximum template " - "instantiation depth">; + "candidate template ignored", + DiagReason<"substitution exceeded maximum template instantiation depth">>; def note_ovl_candidate_underqualified : Note< - "candidate template ignored: cannot deduce a type for %0 that would " - "make %2 equal %1">; + "candidate template ignored", + DiagReason<"cannot deduce a type for %0 that would make %2 equal %1">>; def note_ovl_candidate_substitution_failure : Note< - "candidate template ignored: substitution failure%0%1">; + "candidate template ignored", + DiagReason<"substitution failure%0%1">>; def note_ovl_candidate_disabled_by_enable_if : Note< - "candidate template ignored: disabled by %0%1">; + "candidate template ignored", + DiagReason<"disabled by %0%1">>; def note_ovl_candidate_disabled_by_requirement : Note< - "candidate template ignored: requirement '%0' was not satisfied%1">; + "candidate template ignored", + DiagReason<"requirement '%0' was not satisfied%1">>; def note_ovl_candidate_has_pass_object_size_params: Note< "candidate address cannot be taken because parameter %0 has " "pass_object_size attribute">; Index: clang/include/clang/Basic/DiagnosticSema.h =================================================================== --- clang/include/clang/Basic/DiagnosticSema.h +++ clang/include/clang/Basic/DiagnosticSema.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define SEMASTART #include "clang/Basic/DiagnosticSemaKinds.inc" Index: clang/include/clang/Basic/DiagnosticRefactoring.h =================================================================== --- clang/include/clang/Basic/DiagnosticRefactoring.h +++ clang/include/clang/Basic/DiagnosticRefactoring.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define REFACTORINGSTART #include "clang/Basic/DiagnosticRefactoringKinds.inc" Index: clang/include/clang/Basic/DiagnosticParse.h =================================================================== --- clang/include/clang/Basic/DiagnosticParse.h +++ clang/include/clang/Basic/DiagnosticParse.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define PARSESTART #include "clang/Basic/DiagnosticParseKinds.inc" Index: clang/include/clang/Basic/DiagnosticLex.h =================================================================== --- clang/include/clang/Basic/DiagnosticLex.h +++ clang/include/clang/Basic/DiagnosticLex.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define LEXSTART #include "clang/Basic/DiagnosticLexKinds.inc" Index: clang/include/clang/Basic/DiagnosticIDs.h =================================================================== --- clang/include/clang/Basic/DiagnosticIDs.h +++ clang/include/clang/Basic/DiagnosticIDs.h @@ -67,7 +67,7 @@ // Get typedefs for common diagnostics. enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, CATEGORY, \ - NOWERROR, SHOWINSYSHEADER, SHOWINSYSMACRO, DEFFERABLE) \ + NOWERROR, SHOWINSYSHEADER, SHOWINSYSMACRO, DEFFERABLE, REASON) \ ENUM, #define COMMONSTART #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -160,6 +160,18 @@ } }; +struct DiagnosticReason { + llvm::StringLiteral Value = ""; + + // FIXME(spaceship): default when C++20 becomes the default + bool operator==(const DiagnosticReason &Other) const { return Value == Other.Value; } + bool operator!=(const DiagnosticReason &Other) const { return !(*this == Other); } + bool operator<(const DiagnosticReason &Other) const { return Value < Other.Value; } + bool operator>(const DiagnosticReason &Other) const { return Other < *this; } + bool operator<=(const DiagnosticReason &Other) const { return !(Other < *this); } + bool operator>=(const DiagnosticReason &Other) const { return !(*this < Other); } +}; + /// Used for handling and querying diagnostic IDs. /// /// Can be used and shared by multiple Diagnostics for multiple translation units. @@ -187,7 +199,8 @@ // FIXME: Replace this function with a create-only facilty like // createCustomDiagIDFromFormatString() to enforce safe usage. At the time of // writing, nearly all callers of this function were invalid. - unsigned getCustomDiagID(Level L, StringRef FormatString); + unsigned getCustomDiagID(Level L, StringRef FormatString, + const DiagnosticReason &Reason = {}); //===--------------------------------------------------------------------===// // Diagnostic classification and reporting interfaces. @@ -196,6 +209,9 @@ /// Given a diagnostic ID, return a description of the issue. StringRef getDescription(unsigned DiagID) const; + /// Given a diagnostic ID, return the issue's reason. + StringRef getReason(unsigned DiagID) const; + /// Return true if the unmapped diagnostic levelof the specified /// diagnostic ID is a Warning or Extension. /// Index: clang/include/clang/Basic/DiagnosticFrontend.h =================================================================== --- clang/include/clang/Basic/DiagnosticFrontend.h +++ clang/include/clang/Basic/DiagnosticFrontend.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define FRONTENDSTART #include "clang/Basic/DiagnosticFrontendKinds.inc" Index: clang/include/clang/Basic/DiagnosticDriver.h =================================================================== --- clang/include/clang/Basic/DiagnosticDriver.h +++ clang/include/clang/Basic/DiagnosticDriver.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define DRIVERSTART #include "clang/Basic/DiagnosticDriverKinds.inc" Index: clang/include/clang/Basic/DiagnosticCrossTU.h =================================================================== --- clang/include/clang/Basic/DiagnosticCrossTU.h +++ clang/include/clang/Basic/DiagnosticCrossTU.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define CROSSTUSTART #include "clang/Basic/DiagnosticCrossTUKinds.inc" Index: clang/include/clang/Basic/DiagnosticComment.h =================================================================== --- clang/include/clang/Basic/DiagnosticComment.h +++ clang/include/clang/Basic/DiagnosticComment.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define COMMENTSTART #include "clang/Basic/DiagnosticCommentKinds.inc" Index: clang/include/clang/Basic/DiagnosticAnalysis.h =================================================================== --- clang/include/clang/Basic/DiagnosticAnalysis.h +++ clang/include/clang/Basic/DiagnosticAnalysis.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define ANALYSISSTART #include "clang/Basic/DiagnosticAnalysisKinds.inc" Index: clang/include/clang/Basic/DiagnosticAST.h =================================================================== --- clang/include/clang/Basic/DiagnosticAST.h +++ clang/include/clang/Basic/DiagnosticAST.h @@ -15,7 +15,7 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ ENUM, #define ASTSTART #include "clang/Basic/DiagnosticASTKinds.inc" Index: clang/include/clang/Basic/Diagnostic.td =================================================================== --- clang/include/clang/Basic/Diagnostic.td +++ clang/include/clang/Basic/Diagnostic.td @@ -73,9 +73,16 @@ // This defines all of the named diagnostic groups. include "DiagnosticGroups.td" +// Structured diagnostics enable us to have diagnostics that contain a headline +// description and a detailed description. DiagReason represents the latter, +// although some subengines might combine the two into a single message. +class DiagReason<string value> { + string Value = value; +} +def NO_REASON_YET : DiagReason<"">; // All diagnostics emitted by the compiler are an indirect subclass of this. -class Diagnostic<string summary, DiagClass DC, Severity defaultmapping> { +class Diagnostic<string summary, DiagClass DC, Severity defaultmapping, DiagReason reason> { /// Component is specified by the file with a big let directive. string Component = ?; string Summary = summary; @@ -89,6 +96,7 @@ Severity DefaultSeverity = defaultmapping; DiagGroup Group; string CategoryName = ""; + DiagReason Reason = reason; } class SFINAEFailure { @@ -126,24 +134,24 @@ } // FIXME: ExtWarn and Extension should also be SFINAEFailure by default. -class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure { +class Error<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_ERROR, SEV_Error, reason>, SFINAEFailure { bit ShowInSystemHeader = 1; } // Warnings default to on (but can be default-off'd with DefaultIgnore). // This is used for warnings about questionable code; warnings about // accepted language extensions should use Extension or ExtWarn below instead. -class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>; +class Warning<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_WARNING, SEV_Warning, reason>; // Remarks can be turned on with -R flags and provide commentary, e.g. on // optimizer decisions. -class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>; +class Remark<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_REMARK, SEV_Ignored, reason>; // Extensions are warnings about accepted language extensions. // Extension warnings are default-off but enabled by -pedantic. -class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>; +class Extension<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored, reason>; // ExtWarns are warnings about accepted language extensions. // ExtWarn warnings are default-on. -class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>; +class ExtWarn<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning, reason>; // Notes can provide supplementary information on errors, warnings, and remarks. -class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>; +class Note<string str, DiagReason reason = NO_REASON_YET> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/, reason>; class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; } Index: clang/include/clang/Basic/Diagnostic.h =================================================================== --- clang/include/clang/Basic/Diagnostic.h +++ clang/include/clang/Basic/Diagnostic.h @@ -1666,6 +1666,18 @@ return DiagObj->DiagStorage.FixItHints; } + /// Format the summary into a string, substituting the + /// formal arguments into the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatSummary(SmallVectorImpl<char> &OutStr) const; + + /// Format the reason into a string, substituting the formal arguments into + /// the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatReason(SmallVectorImpl<char> &OutStr) const; + /// Format this diagnostic into a string, substituting the /// formal arguments into the %0 slots. /// @@ -1687,6 +1699,8 @@ DiagnosticsEngine::Level Level; FullSourceLoc Loc; std::string Message; + DiagnosticReason Reason; + std::vector<CharSourceRange> Ranges; std::vector<FixItHint> FixIts; @@ -1694,10 +1708,10 @@ StoredDiagnostic() = default; StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, - StringRef Message); + StringRef Message, DiagnosticReason Reason); StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, - StringRef Message, FullSourceLoc Loc, - ArrayRef<CharSourceRange> Ranges, + StringRef Message, DiagnosticReason Reason, + FullSourceLoc Loc, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Fixits); /// Evaluates true when this object stores a diagnostic. @@ -1707,6 +1721,7 @@ DiagnosticsEngine::Level getLevel() const { return Level; } const FullSourceLoc &getLocation() const { return Loc; } StringRef getMessage() const { return Message; } + const DiagnosticReason &getReason() const { return Reason; } void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } Index: clang-tools-extra/clangd/Diagnostics.cpp =================================================================== --- clang-tools-extra/clangd/Diagnostics.cpp +++ clang-tools-extra/clangd/Diagnostics.cpp @@ -42,7 +42,7 @@ const char *getDiagnosticCode(unsigned ID) { switch (ID) { #define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROPU, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, REASON) \ case clang::diag::ENUM: \ return #ENUM; #include "clang/Basic/DiagnosticASTKinds.inc"
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits