https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/227568
>From f56df0e3a93bdf7e3a0ea975c0ac62a1fb36181d Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Sun, 18 Oct 2026 15:09:07 -0700 Subject: [PATCH] [nspr] initial commit --- .../Support/SourceMgrDiagnosticVerifier.h | 19 ++++-- .../Support/SourceMgrDiagnosticVerifier.cpp | 59 ++++++++++++++----- .../SourceMgrDiagnosticVerifierTest.cpp | 20 +++++++ 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h index 16d87d9e335d4..6bc0335bc9812 100644 --- a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h +++ b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h @@ -23,6 +23,7 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include <optional> +#include <string> namespace llvm { @@ -64,7 +65,15 @@ class LLVM_ABI SourceMgrDiagnosticVerifier { /// diagnostic is reported in them. Verifier errors (near misses, unmatched /// expected diagnostics, malformed directives) are printed to \p OS, /// bypassing \p Mgr's diagnostic handler. - SourceMgrDiagnosticVerifier(const SourceMgr &Mgr, raw_ostream &OS); + /// + /// \p Prefixes are the directive prefixes to recognize (e.g. "expected" + /// for 'expected-error'); they must be non-empty. If \p CommentPrefixes is + /// non-empty, directives are only recognized after the first occurrence of + /// one of these strings on a line, so that text outside of comments is + /// ignored. + SourceMgrDiagnosticVerifier(const SourceMgr &Mgr, raw_ostream &OS, + ArrayRef<StringRef> Prefixes = {"expected"}, + ArrayRef<StringRef> CommentPrefixes = {}); /// Matches a diagnostic against the expected diagnostics for \p Loc, or /// against the '@unknown' expected diagnostics if \p Loc is std::nullopt. @@ -127,9 +136,11 @@ class LLVM_ABI SourceMgrDiagnosticVerifier { const SourceMgr &Mgr; raw_ostream &OS; - /// Regex used to recognize 'expected-<kind>' comments. - Regex Expected{"expected-(error|note|remark|warning)(-re)?" - " *(@([+-][0-9]+|above|below|unknown))? *{{(.*)}}$"}; + /// Regex used to recognize '<prefix>-<kind>' comments. + Regex Expected; + + /// The strings that start a comment, see the constructor. + SmallVector<std::string, 0> CommentPrefixes; /// The expected diagnostics for each buffer that has been scanned so far, /// keyed by buffer identifier (i.e. file name). diff --git a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp index 40c78e18ba74e..6a11c7b95f222 100644 --- a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp +++ b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp @@ -8,14 +8,35 @@ #include "llvm/Support/SourceMgrDiagnosticVerifier.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> using namespace llvm; -SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier(const SourceMgr &Mgr, - raw_ostream &OS) +SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier( + const SourceMgr &Mgr, raw_ostream &OS, ArrayRef<StringRef> Prefixes, + ArrayRef<StringRef> CommentPrefixes) : Mgr(Mgr), OS(OS) { + assert(!Prefixes.empty() && "must have at least one prefix"); + std::string PrefixAlt; + raw_string_ostream PrefixOS(PrefixAlt); + ListSeparator Sep("|"); + for (StringRef Prefix : Prefixes) { + assert(!Prefix.empty() && "prefixes must be non-empty"); + PrefixOS << Sep << Regex::escape(Prefix); + } + // Don't match 'expected' inside a longer word such as 'unexpected'. + Expected = Regex("(^|[^[:alnum:]_-])(" + PrefixAlt + + ")-(error|note|remark|warning)(-re)?" + " *(@([+-][0-9]+|above|below|unknown))? *{{(.*)}}$"); + + for (StringRef Prefix : CommentPrefixes) { + assert(!Prefix.empty() && "comment prefixes must be non-empty"); + this->CommentPrefixes.push_back(Prefix.str()); + } + for (unsigned I = 0, E = Mgr.getNumBuffers(); I != E; ++I) (void)computeExpectedDiags(Mgr.getMemoryBuffer(I + 1)); } @@ -108,12 +129,22 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(const MemoryBuffer *Buf) { // The indices of designators that apply to the next non designator line. SmallVector<unsigned, 1> DesignatorsForNextLine; - // Scan the file for expected-* designators. + // Scan the file for <prefix>-* designators. SmallVector<StringRef, 100> Lines; Buf->getBuffer().split(Lines, '\n'); for (unsigned LineNo = 0, E = Lines.size(); LineNo < E; ++LineNo) { - SmallVector<StringRef, 4> Matches; - if (!Expected.match(Lines[LineNo].rtrim(), &Matches)) { + StringRef Line = Lines[LineNo].rtrim(); + if (!CommentPrefixes.empty()) { + size_t CommentStart = StringRef::npos; + for (StringRef Prefix : CommentPrefixes) + CommentStart = std::min(CommentStart, Line.find(Prefix)); + Line = Line.substr(CommentStart); + } + + // Every directive contains '{{'; check that first to avoid running the + // regex on most lines. + SmallVector<StringRef, 8> Matches; + if (!Line.contains("{{") || !Expected.match(Line, &Matches)) { // Check for designators that apply to this line. if (!DesignatorsForNextLine.empty()) { for (unsigned DiagIndex : DesignatorsForNextLine) @@ -124,27 +155,27 @@ SourceMgrDiagnosticVerifier::computeExpectedDiags(const MemoryBuffer *Buf) { continue; } - // Point to the start of expected-*. - SMLoc ExpectedStart = SMLoc::getFromPointer(Matches[0].data()); + // Point to the start of <prefix>-*. + SMLoc ExpectedStart = SMLoc::getFromPointer(Matches[2].data()); SourceMgr::DiagKind Kind; - if (Matches[1] == "error") + if (Matches[3] == "error") Kind = SourceMgr::DK_Error; - else if (Matches[1] == "warning") + else if (Matches[3] == "warning") Kind = SourceMgr::DK_Warning; - else if (Matches[1] == "remark") + else if (Matches[3] == "remark") Kind = SourceMgr::DK_Remark; else { - assert(Matches[1] == "note"); + assert(Matches[3] == "note"); Kind = SourceMgr::DK_Note; } - ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[5]); + ExpectedDiag Record(Kind, LineNo + 1, ExpectedStart, Matches[7]); // Check to see if this is a regex match, i.e. it includes the `-re`. - if (!Matches[2].empty() && !computeRegex(Record)) + if (!Matches[4].empty() && !computeRegex(Record)) continue; - StringRef OffsetMatch = Matches[3]; + StringRef OffsetMatch = Matches[5]; if (!OffsetMatch.empty()) { OffsetMatch = OffsetMatch.drop_front(1); diff --git a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp index 06e7f19ea2232..6fd5837c35921 100644 --- a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp +++ b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp @@ -121,3 +121,23 @@ TEST_F(SourceMgrDiagnosticVerifierTest, InstalledAsDiagHandler) { StringRef::npos); EXPECT_FALSE(Verifier.verify()); } + +TEST_F(SourceMgrDiagnosticVerifierTest, CustomPrefixesAndCommentScoping) { + const MemoryBuffer *Buf = + addBuffer("op check-error {{outside comment ignored}}\n" + "// check-error@-1 {{first prefix}}\n" + "# alt-warning@-2 {{second prefix}}\n" + "// uncheck-error@-3 {{longer prefix ignored}}\n" + "// other-check-error@-4 {{hyphenated prefix ignored}}\n" + "// expected-error@-5 {{default prefix ignored}}\n"); + SourceMgrDiagnosticVerifier Verifier(SM, OS, {"check", "alt"}, {"//", "#"}); + + EXPECT_EQ( + Verifier.process(getMessage(Buf, SourceMgr::DK_Error, "first prefix")), + MatchResult::Matched); + EXPECT_EQ( + Verifier.process(getMessage(Buf, SourceMgr::DK_Warning, "second prefix")), + MatchResult::Matched); + EXPECT_TRUE(Verifier.verify()); + EXPECT_EQ(Output, ""); +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
