cjdb updated this revision to Diff 479492. cjdb marked 4 inline comments as done. cjdb added a comment.
responds to feedback Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D138939/new/ https://reviews.llvm.org/D138939 Files: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp clang-tools-extra/clangd/Compiler.cpp 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/Basic/PartialDiagnostic.h clang/include/clang/Frontend/ASTUnit.h clang/lib/Basic/Diagnostic.cpp clang/lib/Basic/DiagnosticIDs.cpp clang/lib/Format/TokenAnalyzer.cpp clang/lib/Frontend/ASTUnit.cpp clang/lib/Frontend/LogDiagnosticPrinter.cpp clang/lib/Frontend/SARIFDiagnosticPrinter.cpp clang/lib/Frontend/SerializedDiagnosticPrinter.cpp clang/lib/Frontend/TextDiagnosticBuffer.cpp clang/lib/Frontend/TextDiagnosticPrinter.cpp clang/lib/Sema/SemaOverload.cpp clang/test/Frontend/sarif-reason.cpp clang/test/TableGen/DiagnosticBase.inc clang/test/TableGen/deferred-diag.td clang/tools/clang-format/ClangFormat.cpp clang/tools/clang-import-test/clang-import-test.cpp clang/tools/diagtool/DiagnosticNames.cpp clang/unittests/Driver/SimpleDiagnosticConsumer.h clang/unittests/Driver/ToolChainTest.cpp clang/unittests/Frontend/FrontendActionTest.cpp clang/unittests/Tooling/RewriterTestContext.h clang/utils/TableGen/ClangDiagnosticsEmitter.cpp flang/lib/Frontend/TextDiagnosticBuffer.cpp flang/lib/Frontend/TextDiagnosticPrinter.cpp libcxxabi/test/test_demangle.pass.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -697,7 +697,7 @@ const clang::Diagnostic &info) override { if (m_log) { llvm::SmallVector<char, 32> diag_str(10); - info.FormatDiagnostic(diag_str); + info.FormatLegacyDiagnostic(diag_str); diag_str.push_back('\0'); LLDB_LOGF(m_log, "Compiler diagnostic: %s\n", diag_str.data()); } Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -192,7 +192,7 @@ Log *log = GetLog(LLDBLog::Expressions); if (log) { llvm::SmallVector<char, 32> diag_str; - Info.FormatDiagnostic(diag_str); + Info.FormatLegacyDiagnostic(diag_str); diag_str.push_back('\0'); const char *plain_diag = diag_str.data(); LLDB_LOG(log, "Received diagnostic outside parsing: {0}", plain_diag); Index: flang/lib/Frontend/TextDiagnosticPrinter.cpp =================================================================== --- flang/lib/Frontend/TextDiagnosticPrinter.cpp +++ flang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -37,7 +37,8 @@ // Render the diagnostic message into a temporary buffer eagerly. We'll use // this later as we print out the diagnostic to the terminal. llvm::SmallString<100> outStr; - info.FormatDiagnostic(outStr); + info.FormatSummary(outStr); + info.FormatLegacyDiagnostic(outStr); llvm::raw_svector_ostream diagMessageStream(outStr); Index: flang/lib/Frontend/TextDiagnosticBuffer.cpp =================================================================== --- flang/lib/Frontend/TextDiagnosticBuffer.cpp +++ flang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -29,7 +29,8 @@ DiagnosticConsumer::HandleDiagnostic(level, info); llvm::SmallString<100> buf; - info.FormatDiagnostic(buf); + info.FormatSummary(buf); + info.FormatLegacyDiagnostic(buf); switch (level) { default: llvm_unreachable("Diagnostic not handled during diagnostic buffering!"); 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,17 @@ // Category number. OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); + + // Reasons + OS << ", /*LegacyReason=*/\""; + OS.write_escaped(DiagTextBuilder.buildForDefinition( + R.getValueAsDef("Reason")->getValueAsDef("Legacy"), "Value")) + << '"'; + + OS << ", /*SARIFReason=*/\""; + OS.write_escaped(DiagTextBuilder.buildForDefinition( + R.getValueAsDef("Reason")->getValueAsDef("SARIF"), "Value")) + << '"'; OS << ")\n"; } } Index: clang/unittests/Tooling/RewriterTestContext.h =================================================================== --- clang/unittests/Tooling/RewriterTestContext.h +++ clang/unittests/Tooling/RewriterTestContext.h @@ -35,7 +35,7 @@ const Diagnostic &Info) override { ++NumDiagnosticsSeen; SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); + Info.FormatLegacyDiagnostic(OutStr); llvm::errs() << OutStr; } unsigned NumDiagnosticsSeen; Index: clang/unittests/Frontend/FrontendActionTest.cpp =================================================================== --- clang/unittests/Frontend/FrontendActionTest.cpp +++ clang/unittests/Frontend/FrontendActionTest.cpp @@ -221,10 +221,10 @@ // Capture errors and notes. There should be one of each. if (DiagLevel == DiagnosticsEngine::Error) { assert(Error.empty()); - Info.FormatDiagnostic(Error); + Info.FormatLegacyDiagnostic(Error); } else { assert(Note.empty()); - Info.FormatDiagnostic(Note); + Info.FormatLegacyDiagnostic(Note); } } SmallString<32> Error; Index: clang/unittests/Driver/ToolChainTest.cpp =================================================================== --- clang/unittests/Driver/ToolChainTest.cpp +++ clang/unittests/Driver/ToolChainTest.cpp @@ -378,10 +378,10 @@ const Diagnostic &Info) override { if (DiagLevel == DiagnosticsEngine::Level::Error) { Errors.emplace_back(); - Info.FormatDiagnostic(Errors.back()); + Info.FormatLegacyDiagnostic(Errors.back()); } else { Msgs.emplace_back(); - Info.FormatDiagnostic(Msgs.back()); + Info.FormatLegacyDiagnostic(Msgs.back()); } } void clear() override { Index: clang/unittests/Driver/SimpleDiagnosticConsumer.h =================================================================== --- clang/unittests/Driver/SimpleDiagnosticConsumer.h +++ clang/unittests/Driver/SimpleDiagnosticConsumer.h @@ -21,10 +21,10 @@ const clang::Diagnostic &Info) override { if (DiagLevel == clang::DiagnosticsEngine::Level::Error) { Errors.emplace_back(); - Info.FormatDiagnostic(Errors.back()); + Info.FormatLegacyDiagnostic(Errors.back()); } else { Msgs.emplace_back(); - Info.FormatDiagnostic(Msgs.back()); + Info.FormatLegacyDiagnostic(Msgs.back()); } } void clear() override { Index: clang/tools/diagtool/DiagnosticNames.cpp =================================================================== --- clang/tools/diagtool/DiagnosticNames.cpp +++ clang/tools/diagtool/DiagnosticNames.cpp @@ -28,7 +28,8 @@ // 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, LEGACY_REASON, \ + SARIF_REASON) \ {#ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t)}, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticCrossTUKinds.inc" Index: clang/tools/clang-import-test/clang-import-test.cpp =================================================================== --- clang/tools/clang-import-test/clang-import-test.cpp +++ clang/tools/clang-import-test/clang-import-test.cpp @@ -141,7 +141,7 @@ } SmallString<16> DiagText; - Info.FormatDiagnostic(DiagText); + Info.FormatLegacyDiagnostic(DiagText); llvm::errs() << DiagText << '\n'; if (Info.getLocation().isValid()) { Index: clang/tools/clang-format/ClangFormat.cpp =================================================================== --- clang/tools/clang-format/ClangFormat.cpp +++ clang/tools/clang-format/ClangFormat.cpp @@ -393,7 +393,7 @@ const Diagnostic &Info) override { SmallVector<char, 16> vec; - Info.FormatDiagnostic(vec); + Info.FormatLegacyDiagnostic(vec); errs() << "clang-format error:" << vec << "\n"; } }; 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.Legacy=*/"", /*Reason.SARIF=*/"") 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.Legacy=*/"", /*Reason.SARIF=*/"") 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.Legacy=*/"", /*Reason.SARIF=*/"") 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.Legacy=*/"", /*Reason.SARIF=*/"") // 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.Legacy=*/"", /*Reason.SARIF=*/"") } Index: clang/test/TableGen/DiagnosticBase.inc =================================================================== --- clang/test/TableGen/DiagnosticBase.inc +++ clang/test/TableGen/DiagnosticBase.inc @@ -64,10 +64,34 @@ class InGroup<DiagGroup G> { DiagGroup Group = G; } //class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } +class LegacyR<string value> { + string Value = value; +} + +class SARIF<string value> { + string Value = value; +} + +class DiagReason<LegacyR legacy, SARIF sarif = SARIF<legacy.Value>> { + // A legacy reason is a reason that is part of Clang's legacy diagnostic model, + // but needed to be split from the summary in order to facilitate the existence + // of the structured diagnostic (which will have very different text). One may + // observe that older versions of Clang's diagnostics are the same as + // `Diagnostic.Summary + Diagnostic.Reason.Legacy`. This is intentional, so as + // to preserve the legacy diagnostic model for the time being. + LegacyR Legacy = legacy; + + // The SARIF reason will appear when Clang is asked to emit SARIF diagnostics, + // in place of Legacy. Unlike Legacy, which is a fragment of the original + // diagnostic from past-Clang, SARIF reasons may have completely different text + // to explain the problem, often from the perspective of a user. + SARIF SS = structured; +} +def NO_REASON_YET : DiagReason<LegacyR<"">>; 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 +105,7 @@ Severity DefaultSeverity = defaultmapping; DiagGroup Group; string CategoryName = ""; + DiagReason Reason = reason; } class SFINAEFailure { @@ -118,24 +143,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/test/Frontend/sarif-reason.cpp =================================================================== --- /dev/null +++ clang/test/Frontend/sarif-reason.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only +// RUN: %clang -fsyntax-only -fdiagnostics-format=sarif %s > %t 2>&1 +// RUN: FileCheck -dump-input=always %s --input-file=%t --check-prefix=EXPECTED-ERROR --check-prefix=EXPECTED-NOTE + +template<class T> +void f1(); +template<int T> +void f2(); +template<template<class> class T> +void f3(); + +template<class> struct S; + +void g() { + f1<0>(); // expected-error{{no matching function for call to 'f1'}} + // expected-note@6{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + f1<S>(); // expected-error{{no matching function for call to 'f1'}} + // expected-note@6{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + + f2<int>(); // expected-error{{no matching function for call to 'f2'}} + // expected-note@8{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + f2<S>(); // expected-error{{no matching function for call to 'f2'}} + // expected-note@8{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + + f3<int>(); // expected-error{{no matching function for call to 'f3'}} + // expected-note@10{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + f3<0>(); // expected-error{{no matching function for call to 'f3'}} + // expected-note@10{{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} +} + +// EXPECTED-ERROR: no matching function for call to 'f1' +// EXPECTED-NOTE: candidate template ignored: we passed a value as our first explicit template parameter, but this candidate expects a type for 'T' + +// EXPECTED-ERROR: no matching function for call to 'f1' +// EXPECTED-NOTE: candidate template ignored: we passed a class template as our first explicit template parameter, but this candidate expects a type for 'T' + +// EXPECTED-ERROR: no matching function for call to 'f2' +// EXPECTED-NOTE: candidate template ignored: we passed a type as our first explicit template parameter, but this candidate expects a value for 'T' + +// EXPECTED-ERROR: no matching function for call to 'f2' +// EXPECTED-NOTE: candidate template ignored: we passed a class template as our first explicit template parameter, but this candidate expects a value for 'T' + +// EXPECTED-ERROR: no matching function for call to 'f3' +// EXPECTED-NOTE: candidate template ignored: we passed a type as our first explicit template parameter, but this candidate expects a class template for 'T' + +// EXPECTED-ERROR: no matching function for call to 'f3' +// EXPECTED-NOTE: candidate template ignored: we passed a value as our first explicit template parameter, but this candidate expects a class template for 'T' Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -6511,7 +6511,7 @@ NamedDecl *ND = Function; if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) ND = SpecInfo->getTemplate(); - + if (ND->getFormalLinkage() == Linkage::InternalLinkage) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_module_mismatched; @@ -11108,28 +11108,51 @@ return; } - case Sema::TDK_InvalidExplicitArguments: + case Sema::TDK_InvalidExplicitArguments: { assert(ParamD && "no parameter found for invalid explicit arguments"); + + unsigned index = 1; + int parameter_kind = 0; + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD)) { + index += TTP->getIndex(); + parameter_kind = 0; + } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ParamD)) { + index += NTTP->getIndex(); + parameter_kind = 1; + } else { + index += cast<TemplateTemplateParmDecl>(ParamD)->getIndex(); + parameter_kind = 2; + } + + // QualType CallType = dyn_cast<CallExpr>(Fn)->getType(); + // auto *FT = dyn_cast<FunctionTemplateDecl>(CallType); + // TemplateParameterList *Args = FT->getTemplateParameters(); + // assert(Args && "We should have a full list of template arguments at this + // point"); assert(Args->size() >= index && "The argument list should at + // least be as long as the parameter we're indexing"); + + int arg_kind = 0; + // if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Args->getParam(index - + // 1))) + // arg_kind = 0; + // else if (auto *NTTP = + // dyn_cast<NonTypeTemplateParmDecl>(Args->getParam(index - 1))) + // arg_kind = 1; + // else + // arg_kind = 2; + if (ParamD->getDeclName()) S.Diag(Templated->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_named) - << ParamD->getDeclName(); - else { - int index = 0; - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD)) - index = TTP->getIndex(); - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(ParamD)) - index = NTTP->getIndex(); - else - index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex(); + << ParamD->getDeclName() << arg_kind << index << parameter_kind; + else S.Diag(Templated->getLocation(), diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) - << (index + 1); - } + << index; + MaybeEmitInheritedConstructorNote(S, Found); return; - + } case Sema::TDK_ConstraintsNotSatisfied: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; @@ -13943,8 +13966,8 @@ Diag(FnDecl->getLocation(), diag::note_ovl_ambiguous_oper_binary_reversed_self); // Mark member== const or provide matching != to disallow reversed - // args. Eg. - // struct S { bool operator==(const S&); }; + // args. Eg. + // struct S { bool operator==(const S&); }; // S()==S(); if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl)) if (Op == OverloadedOperatorKind::OO_EqualEqual && Index: clang/lib/Frontend/TextDiagnosticPrinter.cpp =================================================================== --- clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -114,7 +114,7 @@ // Render the diagnostic message into a temporary buffer eagerly. We'll use // this later as we print out the diagnostic to the terminal. SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); + Info.FormatLegacyDiagnostic(OutStr); llvm::raw_svector_ostream DiagMessageStream(OutStr); printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); Index: clang/lib/Frontend/TextDiagnosticBuffer.cpp =================================================================== --- clang/lib/Frontend/TextDiagnosticBuffer.cpp +++ clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -26,7 +26,7 @@ DiagnosticConsumer::HandleDiagnostic(Level, Info); SmallString<100> Buf; - Info.FormatDiagnostic(Buf); + Info.FormatLegacyDiagnostic(Buf); switch (Level) { default: llvm_unreachable( "Diagnostic not handled during diagnostic buffering!"); Index: clang/lib/Frontend/SerializedDiagnosticPrinter.cpp =================================================================== --- clang/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ clang/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -574,7 +574,7 @@ "Received a diagnostic after we've already started teardown."); if (IsFinishing) { SmallString<256> diagnostic; - Info.FormatDiagnostic(diagnostic); + Info.FormatLegacyDiagnostic(diagnostic); getMetaDiags()->Report( diag::warn_fe_serialized_diag_failure_during_finalisation) << diagnostic; @@ -594,7 +594,7 @@ // Compute the diagnostic text. State->diagBuf.clear(); - Info.FormatDiagnostic(State->diagBuf); + Info.FormatLegacyDiagnostic(State->diagBuf); if (Info.getLocation().isInvalid()) { // Special-case diagnostics with no location. We may not have entered a Index: clang/lib/Frontend/SARIFDiagnosticPrinter.cpp =================================================================== --- clang/lib/Frontend/SARIFDiagnosticPrinter.cpp +++ clang/lib/Frontend/SARIFDiagnosticPrinter.cpp @@ -58,7 +58,8 @@ // Render the diagnostic message into a temporary buffer eagerly. We'll use // this later as we add the diagnostic to the SARIF object. SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); + Info.FormatSummary(OutStr); + Info.FormatSARIFReason(OutStr); llvm::raw_svector_ostream DiagMessageStream(OutStr); Index: clang/lib/Frontend/LogDiagnosticPrinter.cpp =================================================================== --- clang/lib/Frontend/LogDiagnosticPrinter.cpp +++ clang/lib/Frontend/LogDiagnosticPrinter.cpp @@ -133,7 +133,7 @@ // Format the message. SmallString<100> MessageStr; - Info.FormatDiagnostic(MessageStr); + Info.FormatLegacyDiagnostic(MessageStr); DE.Message = std::string(MessageStr.str()); // Set the location information. @@ -160,4 +160,3 @@ // Record the diagnostic entry. Entries.push_back(DE); } - 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/Format/TokenAnalyzer.cpp =================================================================== --- clang/lib/Format/TokenAnalyzer.cpp +++ clang/lib/Format/TokenAnalyzer.cpp @@ -44,7 +44,7 @@ if (DiagLevel == DiagnosticsEngine::Fatal) { Fatal = true; llvm::SmallVector<char, 128> Message; - Info.FormatDiagnostic(Message); + Info.FormatLegacyDiagnostic(Message); llvm::errs() << Message << "\n"; } } Index: clang/lib/Basic/DiagnosticIDs.cpp =================================================================== --- clang/lib/Basic/DiagnosticIDs.cpp +++ clang/lib/Basic/DiagnosticIDs.cpp @@ -33,7 +33,8 @@ // 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, \ + LEGACY_REASON, SARIF_REASON) \ char ENUM##_desc[sizeof(DESC)]; // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -54,7 +55,8 @@ const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = { #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ DESC, // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -69,7 +71,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 +81,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, \ + LEGACY_REASON, SARIF_REASON) \ offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc), // clang-format off #include "clang/Basic/DiagnosticCommonKinds.inc" @@ -93,18 +96,158 @@ #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 StaticDiagInfoUnstructuredReasonStringTable { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + char ENUM##_legacy_reason[sizeof(LEGACY_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 StaticDiagInfoUnstructuredReasonStringTable + StaticDiagInfoUnstructuredReasons = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + LEGACY_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 StaticDiagInfoUnstructuredReasonOffsets[] = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + offsetof(StaticDiagInfoUnstructuredReasonStringTable, ENUM##_legacy_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 +}; + +// Reason.SARIF +struct StaticDiagInfoStructuredReasonStringTable { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + char ENUM##_sarif_reason[sizeof(SARIF_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 StaticDiagInfoStructuredReasonStringTable + StaticDiagInfoStructuredReasons = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + SARIF_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 StaticDiagInfoStructuredReasonOffsets[] = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_REASON) \ + offsetof(StaticDiagInfoStructuredReasonStringTable, ENUM##_sarif_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, - CLASS_REMARK = 0x02, - CLASS_WARNING = 0x03, - CLASS_EXTENSION = 0x04, - CLASS_ERROR = 0x05 + CLASS_NOTE = 0x01, + CLASS_REMARK = 0x02, + CLASS_WARNING = 0x03, + CLASS_EXTENSION = 0x04, + CLASS_ERROR = 0x05 }; struct StaticDiagInfoRec { @@ -121,18 +264,35 @@ uint16_t Deferrable : 1; uint16_t DescriptionLen; + uint16_t UnstructuredReasonLen; + uint16_t StructuredReasonLen; - unsigned getOptionGroupIndex() const { - return OptionGroupIndex; - } + unsigned getOptionGroupIndex() const { return OptionGroupIndex; } StringRef getDescription() const { size_t MyIndex = this - &StaticDiagInfo[0]; uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex]; - const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions); + const char *Table = + reinterpret_cast<const char *>(&StaticDiagInfoDescriptions); return StringRef(&Table[StringOffset], DescriptionLen); } + StringRef getUnstructuredReason() const { + size_t MyIndex = this - &StaticDiagInfo[0]; + uint32_t StringOffset = StaticDiagInfoUnstructuredReasonOffsets[MyIndex]; + const char *Table = + reinterpret_cast<const char *>(&StaticDiagInfoUnstructuredReasons); + return StringRef(&Table[StringOffset], UnstructuredReasonLen); + } + + StringRef getStructuredReason() const { + size_t MyIndex = this - &StaticDiagInfo[0]; + uint32_t StringOffset = StaticDiagInfoStructuredReasonOffsets[MyIndex]; + const char *Table = + reinterpret_cast<const char *>(&StaticDiagInfoStructuredReasons); + return StringRef(&Table[StringOffset], StructuredReasonLen); + } + diag::Flavor getFlavor() const { return Class == CLASS_REMARK ? diag::Flavor::Remark : diag::Flavor::WarningOrError; @@ -171,7 +331,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, LEGACY_REASON, SARIF_REASON) \ { \ diag::ENUM, \ DEFAULT_SEVERITY, \ @@ -183,7 +343,9 @@ SHOWINSYSMACRO, \ GROUP, \ DEFERRABLE, \ - STR_SIZE(DESC, uint16_t)}, + STR_SIZE(DESC, uint16_t), \ + STR_SIZE(LEGACY_REASON, uint16_t), \ + STR_SIZE(SARIF_REASON, uint16_t)}, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -222,22 +384,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,16 +443,14 @@ } 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); } +}; +} // namespace // Unfortunately, the split between DiagnosticIDs and Diagnostic is not // particularly clean, but for now we just implement this method here so we can @@ -309,11 +469,10 @@ static const StaticDiagCategoryRec CategoryNameTable[] = { #define GET_CATEGORY_TABLE -#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) }, +#define CATEGORY(X, ENUM) {X, STR_SIZE(X, uint8_t)}, #include "clang/Basic/DiagnosticGroups.inc" #undef GET_CATEGORY_TABLE - { nullptr, 0 } -}; + {nullptr, 0}}; /// getNumberOfCategories - Return the number of categories unsigned DiagnosticIDs::getNumberOfCategories() { @@ -325,12 +484,10 @@ /// invalid. StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { if (CategoryID >= getNumberOfCategories()) - return StringRef(); + return StringRef(); return CategoryNameTable[CategoryID].getName(); } - - DiagnosticIDs::SFINAEResponse DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) @@ -357,47 +514,82 @@ //===----------------------------------------------------------------------===// namespace clang { - namespace diag { - class CustomDiagInfo { - typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc; - std::vector<DiagDesc> DiagInfo; - std::map<DiagDesc, unsigned> DiagIDs; - 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; - } - - /// 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; - } - - unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, - DiagnosticIDs &Diags) { - DiagDesc D(L, std::string(Message)); - // Check to see if it already exists. - std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); - if (I != DiagIDs.end() && I->first == D) - return I->second; - - // If not, assign a new ID. - unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT; - DiagIDs.insert(std::make_pair(D, ID)); - DiagInfo.push_back(D); - return ID; - } - }; - - } // end diag namespace -} // end clang namespace +namespace diag { +class CustomDiagInfo { + 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; + + 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(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Message; + } + + StringRef getLegacyReason(unsigned DiagID) const { + assert(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Reason.Legacy.Value; + } + + StringRef getSARIFReason(unsigned DiagID) const { + assert(IsValidDiagnosticID(DiagID) && "Invalid diagnostic ID"); + return DiagInfo[DiagID - DIAG_UPPER_LIMIT].Reason.SARIF; + } + + /// getLevel - Return the level of the specified custom diagnostic. + DiagnosticIDs::Level getLevel(unsigned DiagID) const { + 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), 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) + return I->second; + + // If not, assign a new ID. + unsigned ID = DiagInfo.size() + DIAG_UPPER_LIMIT; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } +}; + +} // namespace diag +} // namespace clang //===----------------------------------------------------------------------===// // Common Diagnostic implementation @@ -413,13 +605,13 @@ /// /// \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); } - /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic /// level of the specified diagnostic ID is a Warning or Extension. /// This only works on builtin diagnostics, not custom ones, and is not legal to @@ -433,7 +625,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 +634,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 +660,20 @@ return CustomDiagInfo->getDescription(DiagID); } +StringRef DiagnosticIDs::getLegacyReason(unsigned DiagID) const { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->getUnstructuredReason(); + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + return CustomDiagInfo->getLegacyReason(DiagID); +} + +StringRef DiagnosticIDs::getSARIFReason(unsigned DiagID) const { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->getStructuredReason(); + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + return CustomDiagInfo->getSARIFReason(DiagID); +} + static DiagnosticIDs::Level toLevel(diag::Severity SV) { switch (SV) { case diag::Severity::Ignored: @@ -497,7 +703,8 @@ } unsigned DiagClass = getBuiltinDiagClass(DiagID); - if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note; + if (DiagClass == CLASS_NOTE) + return DiagnosticIDs::Note; return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag)); } @@ -603,19 +810,19 @@ #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]); + } +}; +} // namespace // Second the table of options, sorted by name for fast binary lookup. static const WarningOption OptionTable[] = { @@ -694,15 +901,15 @@ // Add the members of the subgroups. const int16_t *SubGroups = DiagSubGroups + Group->SubGroups; for (; *SubGroups != (int16_t)-1; ++SubGroups) - NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups], - Diags); + NotFound &= + getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups], Diags); return NotFound; } -bool -DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, - SmallVectorImpl<diag::kind> &Diags) const { +bool DiagnosticIDs::getDiagnosticsInGroup( + diag::Flavor Flavor, StringRef Group, + SmallVectorImpl<diag::kind> &Diags) const { if (llvm::Optional<diag::Group> G = getGroupForWarningOption(Group)) return ::getDiagnosticsInGroup( Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags); @@ -756,8 +963,8 @@ // Figure out the diagnostic level of this message. unsigned DiagID = Info.getID(); - DiagnosticIDs::Level DiagLevel - = getDiagnosticLevel(DiagID, Info.getLocation(), Diag); + DiagnosticIDs::Level DiagLevel = + getDiagnosticLevel(DiagID, Info.getLocation(), Diag); // Update counts for DiagnosticErrorTrap even if a fatal error occurred // or diagnostics are suppressed. @@ -832,7 +1039,8 @@ void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const { Diagnostic Info(&Diag); - assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!"); + assert(DiagLevel != DiagnosticIDs::Ignored && + "Cannot emit ignored diagnostics!"); Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info); if (Diag.Client->IncludeInDiagnosticCounts()) { 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,21 @@ FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); } +void Diagnostic::FormatLegacyReason(SmallVectorImpl<char> &OutStr) const { + StringRef Diag = getDiags()->getDiagnosticIDs()->getLegacyReason(getID()); + FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); +} + +void Diagnostic::FormatSARIFReason(SmallVectorImpl<char> &OutStr) const { + StringRef Diag = getDiags()->getDiagnosticIDs()->getSARIFReason(getID()); + FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); +} + +void Diagnostic::FormatLegacyDiagnostic(SmallVectorImpl<char> &OutStr) const { + FormatSummary(OutStr); + FormatLegacyReason(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 +1165,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) @@ -1165,20 +1176,20 @@ if (Info.getLocation().isValid()) Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); SmallString<64> Message; - Info.FormatDiagnostic(Message); + Info.FormatSummary(Message); this->Message.assign(Message.begin(), Message.end()); this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end()); this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end()); } 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/PartialDiagnostic.h =================================================================== --- clang/include/clang/Basic/PartialDiagnostic.h +++ clang/include/clang/Basic/PartialDiagnostic.h @@ -170,7 +170,8 @@ // messing with the state of the diagnostics engine. DiagnosticBuilder DB(Diags.Report(getDiagID())); Emit(DB); - Diagnostic(&Diags).FormatDiagnostic(Buf); + Diagnostic Info(&Diags); + Info.FormatLegacyDiagnostic(Buf); DB.Clear(); Diags.Clear(); } Index: clang/include/clang/Basic/DiagnosticSerialization.h =================================================================== --- clang/include/clang/Basic/DiagnosticSerialization.h +++ clang/include/clang/Basic/DiagnosticSerialization.h @@ -15,7 +15,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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 @@ -4515,8 +4515,12 @@ "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< + Legacy<"invalid explicitly-specified argument for template parameter %0">, + SARIF<"we passed a %select{type|value|class template}1 as our %ordinal2 " + "explicit template parameter, but this candidate expects a " + "%select{type|value|class template}3 for template parameter %0">>>; def note_ovl_candidate_unsatisfied_constraints : Note< "candidate template ignored: constraints not satisfied%0">; def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< Index: clang/include/clang/Basic/DiagnosticSema.h =================================================================== --- clang/include/clang/Basic/DiagnosticSema.h +++ clang/include/clang/Basic/DiagnosticSema.h @@ -15,7 +15,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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 @@ -66,9 +66,10 @@ // Get typedefs for common diagnostics. enum { -#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, CATEGORY, \ - NOWERROR, SHOWINSYSHEADER, SHOWINSYSMACRO, DEFFERABLE) \ - ENUM, +#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, CATEGORY, \ + NOWERROR, SHOWINSYSHEADER, SHOWINSYSMACRO, DEFFERABLE, \ + LEGACY_REASON, SARIF_REASON) \ + ENUM, #define COMMONSTART #include "clang/Basic/DiagnosticCommonKinds.inc" NUM_BUILTIN_COMMON_DIAGNOSTICS @@ -160,6 +161,46 @@ } }; +struct LegacyR { + llvm::StringLiteral Value = ""; + + // FIXME(spaceship): default when C++20 becomes the default + bool operator==(const LegacyR &Other) const { return Value == Other.Value; } + bool operator!=(const LegacyR &Other) const { return !(*this == Other); } + bool operator<(const LegacyR &Other) const { return Value < Other.Value; } + bool operator>(const LegacyR &Other) const { return Other < *this; } + bool operator<=(const LegacyR &Other) const { return !(Other < *this); } + bool operator>=(const LegacyR &Other) const { return !(*this < Other); } +}; + +struct DiagnosticReason { + LegacyR Legacy; + llvm::StringLiteral SARIF = ""; + + // FIXME(spaceship): default when C++20 becomes the default + bool operator==(const DiagnosticReason &Other) const { + return Legacy == Other.Legacy && SARIF == Other.SARIF; + } + + bool operator!=(const DiagnosticReason &Other) const { + return !(*this == Other); + } + + bool operator<(const DiagnosticReason &Other) const { + return Legacy < Other.Legacy && SARIF < Other.SARIF; + } + + 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 +228,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 +238,12 @@ /// Given a diagnostic ID, return a description of the issue. StringRef getDescription(unsigned DiagID) const; + /// Given a diagnostic ID, return the issue's legacy reason. + StringRef getLegacyReason(unsigned DiagID) const; + + /// Given a diagnostic ID, return the issue's SARIF reason. + StringRef getSARIFReason(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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,8 @@ namespace diag { enum { #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \ - SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY, \ + LEGACY_REASON, SARIF_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,33 @@ // This defines all of the named diagnostic groups. include "DiagnosticGroups.td" +class Legacy<string value> { + string Value = value; +} + +class SARIF<string value> { + string Value = value; +} + +class DiagReason<Legacy legacy, SARIF structured = SARIF<legacy.Value>> { + // A legacy reason is a reason that is part of Clang's legacy diagnostic model, + // but needed to be split from the summary in order to facilitate the existence + // of the structured diagnostic (which will have very different text). One may + // observe that older versions of Clang's diagnostics are the same as + // `Diagnostic.Summary + Diagnostic.Reason.Legacy`. This is intentional, so as + // to preserve the legacy diagnostic model for the time being. + Legacy Legacy = legacy; + + // The SARIF reason will appear when Clang is asked to emit SARIF diagnostics, + // in place of Legacy. Unlike Legacy, which is a fragment of the original + // diagnostic from past-Clang, SARIF reasons may have completely different text + // to explain the problem, often from the perspective of a user. + SARIF SARIF = structured; +} +def NO_REASON_YET : DiagReason<Legacy<"">, SARIF<"">>; // 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 +113,7 @@ Severity DefaultSeverity = defaultmapping; DiagGroup Group; string CategoryName = ""; + DiagReason Reason = reason; } class SFINAEFailure { @@ -126,24 +151,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,11 +1666,29 @@ return DiagObj->DiagStorage.FixItHints; } - /// Format this diagnostic into a string, substituting the + /// Format the summary into a string, substituting the /// formal arguments into the %0 slots. /// /// The result is appended onto the \p OutStr array. - void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const; + void FormatSummary(SmallVectorImpl<char> &OutStr) const; + + /// Format the legacy reason into a string, substituting the formal arguments + /// into the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatLegacyReason(SmallVectorImpl<char> &OutStr) const; + + /// Format the SARIF-based reason into a string, substituting the formal + /// arguments into the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatSARIFReason(SmallVectorImpl<char> &OutStr) const; + + /// Format the legacy diagnostic into a string, substituting the + /// formal arguments into the %0 slots. + /// + /// The result is appended onto the \p OutStr array. + void FormatLegacyDiagnostic(SmallVectorImpl<char> &OutStr) const; /// Format the given format-string into the output buffer using the /// arguments stored in this diagnostic. @@ -1687,6 +1705,8 @@ DiagnosticsEngine::Level Level; FullSourceLoc Loc; std::string Message; + DiagnosticReason Reason; + std::vector<CharSourceRange> Ranges; std::vector<FixItHint> FixIts; @@ -1694,10 +1714,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 +1727,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,8 @@ 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, \ + LEGACY_REASON, SARIF_REASON) \ case clang::diag::ENUM: \ return #ENUM; #include "clang/Basic/DiagnosticASTKinds.inc" @@ -653,7 +654,7 @@ const clang::Diagnostic &Info, clangd::DiagBase &D) { llvm::SmallString<64> Message; - Info.FormatDiagnostic(Message); + Info.FormatLegacyDiagnostic(Message); D.Message = std::string(Message.str()); D.Severity = DiagLevel; @@ -781,7 +782,8 @@ } } if (Message.empty()) // either !SyntheticMessage, or we failed to make one. - Info.FormatDiagnostic(Message); + Info.FormatSummary(Message); + Info.FormatLegacyDiagnostic(Message); LastDiag->Fixes.push_back( Fix{std::string(Message.str()), std::move(Edits)}); return true; Index: clang-tools-extra/clangd/Compiler.cpp =================================================================== --- clang-tools-extra/clangd/Compiler.cpp +++ clang-tools-extra/clangd/Compiler.cpp @@ -21,7 +21,7 @@ const clang::Diagnostic &Info) { // FIXME: format lazily, in case vlog is off. llvm::SmallString<64> Message; - Info.FormatDiagnostic(Message); + Info.FormatLegacyDiagnostic(Message); llvm::SmallString<64> Location; if (Info.hasSourceManager() && Info.getLocation().isValid()) { Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -418,7 +418,7 @@ Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(), Errors.back()); SmallString<100> Message; - Info.FormatDiagnostic(Message); + Info.FormatLegacyDiagnostic(Message); FullSourceLoc Loc; if (Info.getLocation().isValid() && Info.hasSourceManager()) Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits