Skip to content

Conversation

vitalybuka
Copy link
Collaborator

This extends approach used in WarningsSpecialCaseList
on other types of SpecialCaseList.

SpecialCaseList will remove leading "./" from the Query
for prefixes which looks like file names.

Now affected prefixes are "src", "!src", "mainfile", "source".

To avoid breaking users, this behavior is enabled for
files starting "#!special-case-list-v3".

Created using spr 1.3.6
@llvmbot
Copy link
Member

llvmbot commented Oct 8, 2025

@llvm/pr-subscribers-llvm-support

Author: Vitaly Buka (vitalybuka)

Changes

This extends approach used in WarningsSpecialCaseList
on other types of SpecialCaseList.

SpecialCaseList will remove leading "./" from the Query
for prefixes which looks like file names.

Now affected prefixes are "src", "!src", "mainfile", "source".

To avoid breaking users, this behavior is enabled for
files starting "#!special-case-list-v3".


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

3 Files Affected:

  • (modified) llvm/include/llvm/Support/SpecialCaseList.h (+1)
  • (modified) llvm/lib/Support/SpecialCaseList.cpp (+9)
  • (modified) llvm/unittests/Support/SpecialCaseListTest.cpp (+51-12)
diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h
index 64cad804ad911..d8dd1c4ec4bbc 100644
--- a/llvm/include/llvm/Support/SpecialCaseList.h
+++ b/llvm/include/llvm/Support/SpecialCaseList.h
@@ -156,6 +156,7 @@ class SpecialCaseList {
 
     std::vector<std::unique_ptr<Matcher::Glob>> Globs;
     std::vector<std::unique_ptr<Reg>> RegExes;
+    bool RemoveDotSlash = false;
   };
 
   using SectionEntries = StringMap<StringMap<Matcher>>;
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index 6ad8d7d4e7ffa..636dc5e651f56 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -22,6 +22,7 @@
 #include "llvm/Support/VirtualFileSystem.h"
 #include <algorithm>
 #include <limits>
+#include <memory>
 #include <stdio.h>
 #include <string>
 #include <system_error>
@@ -72,6 +73,8 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
 void SpecialCaseList::Matcher::match(
     StringRef Query,
     llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const {
+  if (RemoveDotSlash)
+    Query = llvm::sys::path::remove_leading_dotslash(Query);
   for (const auto &Glob : reverse(Globs))
     if (Glob->Pattern.match(Query))
       Cb(Glob->Name, Glob->LineNo);
@@ -164,12 +167,16 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
   // https://discourse.llvm.org/t/use-glob-instead-of-regex-for-specialcaselists/71666
   bool UseGlobs = Version > 1;
 
+  bool RemoveDotSlash = Version > 2;
+
   Section *CurrentSection;
   if (auto Err = addSection("*", FileIdx, 1).moveInto(CurrentSection)) {
     Error = toString(std::move(Err));
     return false;
   }
 
+  constexpr StringRef PathPrefixes[] = {"src", "!src", "mainfile", "source"};
+
   for (line_iterator LineIt(*MB, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
        !LineIt.is_at_eof(); LineIt++) {
     unsigned LineNo = LineIt.line_number();
@@ -205,6 +212,8 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
 
     auto [Pattern, Category] = Postfix.split("=");
     auto &Entry = CurrentSection->Entries[Prefix][Category];
+    Entry.RemoveDotSlash =
+        RemoveDotSlash && llvm::is_contained(PathPrefixes, Prefix);
     if (auto Err = Entry.insert(Pattern, LineNo, UseGlobs)) {
       Error =
           (Twine("malformed ") + (UseGlobs ? "glob" : "regex") + " in line " +
diff --git a/llvm/unittests/Support/SpecialCaseListTest.cpp b/llvm/unittests/Support/SpecialCaseListTest.cpp
index 5be2b9e3a7a5d..df6ee78f0933e 100644
--- a/llvm/unittests/Support/SpecialCaseListTest.cpp
+++ b/llvm/unittests/Support/SpecialCaseListTest.cpp
@@ -22,33 +22,31 @@ namespace {
 
 class SpecialCaseListTest : public ::testing::Test {
 protected:
-  std::unique_ptr<SpecialCaseList> makeSpecialCaseList(StringRef List,
-                                                       std::string &Error,
-                                                       bool UseGlobs = true) {
+  std::unique_ptr<SpecialCaseList>
+  makeSpecialCaseList(StringRef List, std::string &Error, int Version = 0) {
     auto S = List.str();
-    if (!UseGlobs)
-      S = (Twine("#!special-case-list-v1\n") + S).str();
+    if (Version)
+      S = (Twine("#!special-case-list-v") + Twine(Version) + "\n" + S).str();
     std::unique_ptr<MemoryBuffer> MB = MemoryBuffer::getMemBuffer(S);
     return SpecialCaseList::create(MB.get(), Error);
   }
 
   std::unique_ptr<SpecialCaseList> makeSpecialCaseList(StringRef List,
-                                                       bool UseGlobs = true) {
+                                                       int Version = 0) {
     std::string Error;
-    auto SCL = makeSpecialCaseList(List, Error, UseGlobs);
+    auto SCL = makeSpecialCaseList(List, Error, Version);
     assert(SCL);
     assert(Error == "");
     return SCL;
   }
 
-  std::string makeSpecialCaseListFile(StringRef Contents,
-                                      bool UseGlobs = true) {
+  std::string makeSpecialCaseListFile(StringRef Contents, int Version = 0) {
     int FD;
     SmallString<64> Path;
     sys::fs::createTemporaryFile("SpecialCaseListTest", "temp", FD, Path);
     raw_fd_ostream OF(FD, true, true);
-    if (!UseGlobs)
-      OF << "#!special-case-list-v1\n";
+    if (Version)
+      OF << "#!special-case-list-v" << Version << "\n";
     OF << Contents;
     OF.close();
     return std::string(Path.str());
@@ -261,7 +259,7 @@ TEST_F(SpecialCaseListTest, Version1) {
                           "fun:foo.*\n"
                           "fun:abc|def\n"
                           "fun:b.r\n",
-                          /*UseGlobs=*/false);
+                          /*Version=*/1);
 
   EXPECT_TRUE(SCL->inSection("sect1", "fun", "fooz"));
   EXPECT_TRUE(SCL->inSection("sect2", "fun", "fooz"));
@@ -283,6 +281,47 @@ TEST_F(SpecialCaseListTest, Version1) {
   EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar"));
 }
 
+TEST_F(SpecialCaseListTest, DotSlash) {
+  std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[sect1]\n"
+                                                             "fun:./foo\n"
+                                                             "src:./bar\n"
+                                                             "[sect2]\n"
+                                                             "fun:foo\n"
+                                                             "src:bar\n");
+  EXPECT_TRUE(SCL->inSection("sect1", "fun", "./foo"));
+  EXPECT_FALSE(SCL->inSection("sect1", "fun", "foo"));
+
+  EXPECT_TRUE(SCL->inSection("sect1", "src", "./bar"));
+  EXPECT_FALSE(SCL->inSection("sect1", "src", "bar"));
+
+  EXPECT_FALSE(SCL->inSection("sect2", "fun", "./foo"));
+  EXPECT_TRUE(SCL->inSection("sect2", "fun", "foo"));
+
+  EXPECT_FALSE(SCL->inSection("sect2", "src", "./bar"));
+  EXPECT_TRUE(SCL->inSection("sect2", "src", "bar"));
+}
+
+TEST_F(SpecialCaseListTest, DotSlashV3) {
+  std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[sect1]\n"
+                                                             "fun:./foo\n"
+                                                             "src:./bar\n"
+                                                             "[sect2]\n"
+                                                             "fun:foo\n"
+                                                             "src:bar\n",
+                                                             /*Version=*/3);
+  EXPECT_TRUE(SCL->inSection("sect1", "fun", "./foo"));
+  EXPECT_FALSE(SCL->inSection("sect1", "fun", "foo"));
+
+  EXPECT_FALSE(SCL->inSection("sect1", "src", "./bar"));
+  EXPECT_FALSE(SCL->inSection("sect1", "src", "bar"));
+
+  EXPECT_FALSE(SCL->inSection("sect2", "fun", "./foo"));
+  EXPECT_TRUE(SCL->inSection("sect2", "fun", "foo"));
+
+  EXPECT_TRUE(SCL->inSection("sect2", "src", "./bar"));
+  EXPECT_TRUE(SCL->inSection("sect2", "src", "bar"));
+}
+
 TEST_F(SpecialCaseListTest, Version2) {
   std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("[{sect1,sect2}]\n"
                                                              "fun:foo*\n"

Created using spr 1.3.6
@vitalybuka vitalybuka enabled auto-merge (squash) October 8, 2025 16:38
@vitalybuka vitalybuka disabled auto-merge October 8, 2025 17:03
Added comments to clarify the purpose of PathPrefixes.
@vitalybuka vitalybuka enabled auto-merge (squash) October 8, 2025 17:20
@vitalybuka vitalybuka merged commit 466f691 into main Oct 8, 2025
7 of 8 checks passed
@vitalybuka vitalybuka deleted the users/vitalybuka/spr/specialcaselist-remove-from-file-path branch October 8, 2025 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants