https://github.com/arichardson updated https://github.com/llvm/llvm-project/pull/227568
>From ae13303b52ae3cdbab6d1e955c0d50466d69ab78 Mon Sep 17 00:00:00 2001 From: Alex Richardson <[email protected]> Date: Sun, 18 Oct 2026 12:40:41 -0700 Subject: [PATCH] [nspr] initial commit --- .../Support/SourceMgrDiagnosticVerifier.h | 25 ++++++-- .../Support/SourceMgrDiagnosticVerifier.cpp | 60 +++++++++++++++---- .../SourceMgrDiagnosticVerifierTest.cpp | 20 +++++++ 3 files changed, 89 insertions(+), 16 deletions(-) diff --git a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h index 0c1dc380065c1..9252b926eabb6 100644 --- a/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h +++ b/llvm/include/llvm/Support/SourceMgrDiagnosticVerifier.h @@ -60,8 +60,19 @@ class LLVM_ABI SourceMgrDiagnosticVerifier { /// diagnostics. /// \param OS The stream to which verifier diagnostics (near misses, /// unmatched expected diagnostics, malformed directives) are printed. - explicit SourceMgrDiagnosticVerifier(const SourceMgr &Mgr, - raw_ostream &OS = errs()); + /// \param Prefixes The comment prefixes that introduce an expected + /// diagnostic, e.g. \c {"expected"} to recognize 'expected-error'. Matched + /// literally, not as a regex. Must be non-empty and must not contain an + /// empty string. + /// \param CommentPrefixes If non-empty, only text at or after the earliest + /// occurrence of one of these strings on a line is scanned for expected + /// diagnostics, so a magic string that happens to appear outside of a + /// comment (e.g. in an instruction operand) is ignored. Must not contain an + /// empty string. If empty, the whole line is eligible. + explicit SourceMgrDiagnosticVerifier( + const SourceMgr &Mgr, raw_ostream &OS = errs(), + ArrayRef<std::string> Prefixes = {"expected"}, + ArrayRef<std::string> CommentPrefixes = {}); /// Matches a single actual diagnostic against the expected diagnostics /// recorded for \p Buf / \p LineNo, scanning \p Buf first if it hasn't been @@ -132,9 +143,13 @@ 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, built from the + /// \p Prefixes passed to the constructor. + Regex Expected; + + /// If non-empty, only text at or after the earliest occurrence of one of + /// these strings on a line is eligible to match \p Expected. + std::vector<std::string> CommentPrefixes; /// The expected diagnostics for each buffer that has been scanned so far. DenseMap<const MemoryBuffer *, SmallVector<ExpectedDiag, 2>> diff --git a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp index 71f4b0e1c1c1b..7efca8ce20d4c 100644 --- a/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp +++ b/llvm/lib/Support/SourceMgrDiagnosticVerifier.cpp @@ -8,15 +8,41 @@ #include "llvm/Support/SourceMgrDiagnosticVerifier.h" +#include <algorithm> + +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier(const SourceMgr &Mgr, - raw_ostream &OS) - : Mgr(Mgr), OS(OS) {} +SourceMgrDiagnosticVerifier::SourceMgrDiagnosticVerifier( + const SourceMgr &Mgr, raw_ostream &OS, ArrayRef<std::string> Prefixes, + ArrayRef<std::string> CommentPrefixes) + : Mgr(Mgr), OS(OS), + CommentPrefixes(CommentPrefixes.begin(), CommentPrefixes.end()) { + assert(!Prefixes.empty() && "must have at least one prefix"); + assert( + llvm::all_of(CommentPrefixes, [](StringRef P) { return !P.empty(); }) && + "comment prefixes must be non-empty"); + std::string PrefixAlt; + raw_string_ostream PrefixOS(PrefixAlt); + ListSeparator Sep("|"); + for (const std::string &Prefix : Prefixes) { + assert(!Prefix.empty() && "prefixes must be non-empty"); + PrefixOS << Sep << Regex::escape(Prefix); + } + // Require start-of-line or a non-[[:alnum:]_-] character before the prefix + // so that e.g. 'check' or 'expected' does not match the suffix of a longer + // prefix like 'uncheck-error' or 'foo-expected-error'. + // clang-format off + Expected = Regex("(^|[^[:alnum:]_-])(" + PrefixAlt + + ")-(error|note|remark|warning)(-re)?" + " *(@([+-][0-9]+|above|below|unknown))?" + " *{{(.*)}}$"); + // clang-format on +} /// Given a diagnostic kind, return a human readable string for it. static StringRef getDiagKindStr(SourceMgr::DiagKind Kind) { @@ -108,12 +134,24 @@ 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) { + // If comment-scoping is enabled, only the text at or after the earliest + // recognized comment prefix on the line is eligible to match, so a magic + // string appearing outside of a comment (e.g. in an instruction operand) + // is ignored. + 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); + } + SmallVector<StringRef, 10> Matches; - if (!Expected.match(Lines[LineNo].rtrim(), &Matches)) { + if (!Expected.match(Line, &Matches)) { // Check for designators that apply to this line. if (!DesignatorsForNextLine.empty()) { for (unsigned DiagIndex : DesignatorsForNextLine) @@ -124,21 +162,21 @@ 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 = StringSwitch<SourceMgr::DiagKind>(Matches[1]) + SourceMgr::DiagKind Kind = StringSwitch<SourceMgr::DiagKind>(Matches[3]) .Case("error", SourceMgr::DK_Error) .Case("warning", SourceMgr::DK_Warning) .Case("remark", SourceMgr::DK_Remark) .Case("note", 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 1e7f65e2c0b79..222ed92ce5df1 100644 --- a/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp +++ b/llvm/unittests/Support/SourceMgrDiagnosticVerifierTest.cpp @@ -172,3 +172,23 @@ TEST_F(SourceMgrDiagnosticVerifierTest, AlreadyMatchedDoesNotTriggerNearMiss) { EXPECT_EQ(StringRef(Output).find("diagnostic emitted when expecting"), StringRef::npos); } + +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"); + SourceMgrDiagnosticVerifier Verifier(SM, OS, {"check", "alt"}, {"//", "#"}); + + SMLoc Loc = SMLoc::getFromPointer(Buf->getBufferStart()); + EXPECT_EQ( + Verifier.process(SM.GetMessage(Loc, SourceMgr::DK_Error, "first prefix")), + MatchResult::Matched); + EXPECT_EQ(Verifier.process( + SM.GetMessage(Loc, 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
