From be5e1370690ccfe174800dd7f5f733373ea3ed70 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Oct 2025 01:18:12 -0700 Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.6 --- llvm/include/llvm/Support/SpecialCaseList.h | 1 + llvm/lib/Support/SpecialCaseList.cpp | 9 +++ .../unittests/Support/SpecialCaseListTest.cpp | 63 +++++++++++++++---- 3 files changed, 61 insertions(+), 12 deletions(-) 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> Globs; std::vector> RegExes; + bool RemoveDotSlash = false; }; using SectionEntries = StringMap>; 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 #include +#include #include #include #include @@ -72,6 +73,8 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber, void SpecialCaseList::Matcher::match( StringRef Query, llvm::function_ref 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 makeSpecialCaseList(StringRef List, - std::string &Error, - bool UseGlobs = true) { + std::unique_ptr + 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 MB = MemoryBuffer::getMemBuffer(S); return SpecialCaseList::create(MB.get(), Error); } std::unique_ptr 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 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 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 SCL = makeSpecialCaseList("[{sect1,sect2}]\n" "fun:foo*\n" From 1bddb6e4e09782ac611c786723fc4c5b27189d32 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Oct 2025 09:35:29 -0700 Subject: [PATCH 2/3] side-by-side test Created using spr 1.3.6 --- .../unittests/Support/SpecialCaseListTest.cpp | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/llvm/unittests/Support/SpecialCaseListTest.cpp b/llvm/unittests/Support/SpecialCaseListTest.cpp index df6ee78f0933e..750fedaf0a436 100644 --- a/llvm/unittests/Support/SpecialCaseListTest.cpp +++ b/llvm/unittests/Support/SpecialCaseListTest.cpp @@ -281,47 +281,6 @@ TEST_F(SpecialCaseListTest, Version1) { EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar")); } -TEST_F(SpecialCaseListTest, DotSlash) { - std::unique_ptr 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 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 SCL = makeSpecialCaseList("[{sect1,sect2}]\n" "fun:foo*\n" @@ -348,6 +307,46 @@ TEST_F(SpecialCaseListTest, Version2) { EXPECT_FALSE(SCL->inSection("sect3", "fun", "bar")); } +TEST_F(SpecialCaseListTest, DotSlash) { + std::unique_ptr SCL2 = makeSpecialCaseList("[dot]\n" + "fun:./foo\n" + "src:./bar\n" + "[not]\n" + "fun:foo\n" + "src:bar\n"); + std::unique_ptr SCL3 = makeSpecialCaseList("[dot]\n" + "fun:./foo\n" + "src:./bar\n" + "[not]\n" + "fun:foo\n" + "src:bar\n", + /*Version=*/3); + + EXPECT_TRUE(SCL2->inSection("dot", "fun", "./foo")); + EXPECT_TRUE(SCL3->inSection("dot", "fun", "./foo")); + + EXPECT_FALSE(SCL2->inSection("dot", "fun", "foo")); + EXPECT_FALSE(SCL3->inSection("dot", "fun", "foo")); + + EXPECT_TRUE(SCL2->inSection("dot", "src", "./bar")); + EXPECT_FALSE(SCL3->inSection("dot", "src", "./bar")); + + EXPECT_FALSE(SCL2->inSection("dot", "src", "bar")); + EXPECT_FALSE(SCL3->inSection("dot", "src", "bar")); + + EXPECT_FALSE(SCL2->inSection("not", "fun", "./foo")); + EXPECT_FALSE(SCL3->inSection("not", "fun", "./foo")); + + EXPECT_TRUE(SCL2->inSection("not", "fun", "foo")); + EXPECT_TRUE(SCL3->inSection("not", "fun", "foo")); + + EXPECT_FALSE(SCL2->inSection("not", "src", "./bar")); + EXPECT_TRUE(SCL3->inSection("not", "src", "./bar")); + + EXPECT_TRUE(SCL2->inSection("not", "src", "bar")); + EXPECT_TRUE(SCL3->inSection("not", "src", "bar")); +} + TEST_F(SpecialCaseListTest, LinesInSection) { std::unique_ptr SCL = makeSpecialCaseList("fun:foo\n" "fun:bar\n" From d41a1cab03cd36030214d5f18f1e8768163dda00 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 8 Oct 2025 10:10:23 -0700 Subject: [PATCH 3/3] Add comments for PathPrefixes in SpecialCaseList Added comments to clarify the purpose of PathPrefixes. --- llvm/lib/Support/SpecialCaseList.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp index 636dc5e651f56..6c684376d493c 100644 --- a/llvm/lib/Support/SpecialCaseList.cpp +++ b/llvm/lib/Support/SpecialCaseList.cpp @@ -175,6 +175,8 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB, return false; } + // This is the current list of prefixes for all existing users matching file + // path. We may need parametrization in constructor in future. constexpr StringRef PathPrefixes[] = {"src", "!src", "mainfile", "source"}; for (line_iterator LineIt(*MB, /*SkipBlanks=*/true, /*CommentMarker=*/'#');