Skip to content

Conversation

vitalybuka
Copy link
Collaborator

There are some users who rely on more than line
number. It would be easy to move some logic from
users side here with extracted methods.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" llvm:support labels Oct 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2025

@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-clang

Author: Vitaly Buka (vitalybuka)

Changes

There are some users who rely on more than line
number. It would be easy to move some logic from
users side here with extracted methods.


Full diff: https://github.com/llvm/llvm-project/pull/162397.diff

3 Files Affected:

  • (modified) clang/lib/Basic/SanitizerSpecialCaseList.cpp (+1-1)
  • (modified) llvm/include/llvm/Support/SpecialCaseList.h (+18-3)
  • (modified) llvm/lib/Support/SpecialCaseList.cpp (+28-13)
diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
index a1dc4a7ec99bf..792000b545fb8 100644
--- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp
+++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -42,7 +42,7 @@ void SanitizerSpecialCaseList::createSanitizerSections() {
     SanitizerMask Mask;
 
 #define SANITIZER(NAME, ID)                                                    \
-  if (S.SectionMatcher.match(NAME))                                            \
+  if (S.SectionMatcher.matchAny(NAME))                                         \
     Mask |= SanitizerKind::ID;
 #define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)
 
diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h
index 55d3d12dc3d5f..bb382f64b084f 100644
--- a/llvm/include/llvm/Support/SpecialCaseList.h
+++ b/llvm/include/llvm/Support/SpecialCaseList.h
@@ -123,9 +123,15 @@ class SpecialCaseList {
   public:
     LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber,
                           bool UseRegex);
-    // Returns the line number in the source file that this query matches to.
-    // Returns zero if no match is found.
-    LLVM_ABI unsigned match(StringRef Query) const;
+    LLVM_ABI void
+    match(StringRef Query,
+          llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const;
+
+    LLVM_ABI bool matchAny(StringRef Query) const {
+      bool R = false;
+      match(Query, [&](StringRef, unsigned) { R = true; });
+      return R;
+    }
 
     struct Glob {
       std::string Name;
@@ -158,6 +164,15 @@ class SpecialCaseList {
     // 1-based line number on which rule is defined, or 0 if there is no match.
     LLVM_ABI unsigned getLastMatch(StringRef Prefix, StringRef Query,
                                    StringRef Category) const;
+
+    // Helper method to search by Prefix, Query, and Category. Returns
+    // matching rule, or empty string if there is no match.
+    LLVM_ABI StringRef getLongestMatch(StringRef Prefix, StringRef Query,
+                                       StringRef Category) const;
+
+  private:
+    LLVM_ABI const SpecialCaseList::Matcher *
+    findMatcher(StringRef Prefix, StringRef Category) const;
   };
 
   std::vector<Section> Sections;
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index be57a5db6ce05..1e43bedfcfb4c 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -20,7 +20,7 @@
 #include "llvm/Support/LineIterator.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/VirtualFileSystem.h"
-#include <limits>
+#include <algorithm>
 #include <stdio.h>
 #include <string>
 #include <system_error>
@@ -69,14 +69,15 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
   return Error::success();
 }
 
-unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
+void SpecialCaseList::Matcher::match(
+    StringRef Query,
+    llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const {
   for (const auto &Glob : reverse(Globs))
     if (Glob->Pattern.match(Query))
-      return Glob->LineNo;
+      Cb(Glob->Name, Glob->LineNo);
   for (const auto &[Regex, LineNumber] : reverse(RegExes))
     if (Regex->match(Query))
-      return LineNumber;
-  return 0;
+      Cb(/*FIXME: there is no users of this param yet */ "", LineNumber);
 }
 
 // TODO: Refactor this to return Expected<...>
@@ -169,7 +170,9 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
     return false;
   }
 
-  for (line_iterator LineIt(*MB, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
+  for (line_iterator LineIt(*MB, /*SkipBlanks=*/
+                            true,
+                            /*CommentMarker=*/'#');
        !LineIt.is_at_eof(); LineIt++) {
     unsigned LineNo = LineIt.line_number();
     StringRef Line = LineIt->trim();
@@ -227,7 +230,7 @@ std::pair<unsigned, unsigned>
 SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
                                 StringRef Query, StringRef Category) const {
   for (const auto &S : reverse(Sections)) {
-    if (S.SectionMatcher.match(Section)) {
+    if (S.SectionMatcher.matchAny(Section)) {
       unsigned Blame = S.getLastMatch(Prefix, Query, Category);
       if (Blame)
         return {S.FileIdx, Blame};
@@ -236,17 +239,29 @@ SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
   return NotFound;
 }
 
-unsigned SpecialCaseList::Section::getLastMatch(StringRef Prefix,
-                                                StringRef Query,
-                                                StringRef Category) const {
+const SpecialCaseList::Matcher *
+SpecialCaseList::Section::findMatcher(StringRef Prefix,
+                                      StringRef Category) const {
   SectionEntries::const_iterator I = Entries.find(Prefix);
   if (I == Entries.end())
-    return 0;
+    return nullptr;
   StringMap<Matcher>::const_iterator II = I->second.find(Category);
   if (II == I->second.end())
-    return 0;
+    return nullptr;
+
+  return &II->second;
+}
 
-  return II->getValue().match(Query);
+unsigned SpecialCaseList::Section::getLastMatch(StringRef Prefix,
+                                                StringRef Query,
+                                                StringRef Category) const {
+  unsigned LastLine = 0;
+  if (const Matcher *M = findMatcher(Prefix, Category)) {
+    M->match(Query, [&](StringRef, unsigned LineNo) {
+      LastLine = std::max(LastLine, LineNo);
+    });
+  }
+  return LastLine;
 }
 
 } // namespace llvm

Created using spr 1.3.6
Created using spr 1.3.6

[skip ci]
@vitalybuka vitalybuka changed the base branch from users/vitalybuka/spr/main.nfcspecialcaselist-extract-findmatcher-and-match-with-callback to main October 8, 2025 00:10
Created using spr 1.3.6
@vitalybuka vitalybuka enabled auto-merge (squash) October 8, 2025 00:11
@vitalybuka vitalybuka merged commit aed53d1 into main Oct 8, 2025
7 of 8 checks passed
@vitalybuka vitalybuka deleted the users/vitalybuka/spr/nfcspecialcaselist-extract-findmatcher-and-match-with-callback branch October 8, 2025 00:42
svkeerthy pushed a commit that referenced this pull request Oct 9, 2025
…162397)

There are some users who rely on more than line
number. It would be easy to move some logic from
users side here with extracted methods.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants