https://github.com/DKLoehr updated https://github.com/llvm/llvm-project/pull/149886
>From 028be83a047f7dc3e5ff7d89f62ce4bd7452ff1b Mon Sep 17 00:00:00 2001 From: Devon Loehr <dlo...@google.com> Date: Mon, 21 Jul 2025 19:07:23 +0000 Subject: [PATCH 1/4] Make special case matcher slash-agnostic --- clang/docs/SanitizerSpecialCaseList.rst | 1 + clang/unittests/Basic/DiagnosticTest.cpp | 23 +++++++++++++++++++++++ llvm/docs/ReleaseNotes.md | 4 ++++ llvm/include/llvm/Support/GlobPattern.h | 1 + llvm/lib/Support/GlobPattern.cpp | 4 ++++ 5 files changed, 33 insertions(+) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index 307c001664fba..f2a04dc9adcf1 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -174,6 +174,7 @@ tool-specific docs. # Lines starting with # are ignored. # Turn off checks for the source file # Entries without sections are placed into [*] and apply to all sanitizers + # "/" matches both windows and unix path separators ("/" and "\") src:path/to/source/file.c src:*/source/file.c # Turn off checks for this main file, including files included by it. diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp index 4b3af00c3b0ce..a6557b1e35c4b 100644 --- a/clang/unittests/Basic/DiagnosticTest.cpp +++ b/clang/unittests/Basic/DiagnosticTest.cpp @@ -360,4 +360,27 @@ TEST_F(SuppressionMappingTest, ParsingRespectsOtherWarningOpts) { clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS); EXPECT_THAT(diags(), IsEmpty()); } + +TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) { + llvm::StringLiteral SuppressionMappingFile = R"( + [unused] + src:*clang/* + src:*clang/lib/Sema/*=emit + src:*clang/lib\\Sema/foo*)"; + Diags.getDiagnosticOptions().DiagnosticSuppressionMappingsFile = "foo.txt"; + FS->addFile("foo.txt", /*ModificationTime=*/{}, + llvm::MemoryBuffer::getMemBuffer(SuppressionMappingFile)); + clang::ProcessWarningOptions(Diags, Diags.getDiagnosticOptions(), *FS); + EXPECT_THAT(diags(), IsEmpty()); + + EXPECT_TRUE(Diags.isSuppressedViaMapping( + diag::warn_unused_function, locForFile(R"(clang/lib/Basic/foo.h)"))); + EXPECT_FALSE(Diags.isSuppressedViaMapping( + diag::warn_unused_function, locForFile(R"(clang/lib/Sema\bar.h)"))); + EXPECT_TRUE(Diags.isSuppressedViaMapping( + diag::warn_unused_function, locForFile(R"(clang\lib\Sema/foo.h)"))); + // The third pattern requires a literal backslash before Sema + EXPECT_FALSE(Diags.isSuppressedViaMapping( + diag::warn_unused_function, locForFile(R"(clang/lib/Sema/foo.h)"))); +} } // namespace diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 5640c72c1d7a0..d677ce865dc69 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -165,6 +165,10 @@ Changes to BOLT Changes to Sanitizers --------------------- +* The [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format) + now treats forward slashes as either a forward or a backslash, to handle + paths with mixed unix and window styles. + Other Changes ------------- diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index 62ed4a0f23fd9..af92c63331282 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -35,6 +35,7 @@ namespace llvm { /// expansions are not supported. If \p MaxSubPatterns is empty then /// brace expansions are not supported and characters `{,}` are treated as /// literals. +/// * `/` matches both unix and windows path separators: `/` and `\`. /// * `\` escapes the next character so it is treated as a literal. /// /// Some known edge cases are: diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp index 7004adf461a0c..26b3724863ee8 100644 --- a/llvm/lib/Support/GlobPattern.cpp +++ b/llvm/lib/Support/GlobPattern.cpp @@ -231,6 +231,10 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const { ++S; continue; } + } else if (*P == '/' && (*S == '/' || *S == '\\')) { + ++P; + ++S; + continue; } else if (*P == *S || *P == '?') { ++P; ++S; >From e9820cb21b139e372dacfda0e83eab5cff214338 Mon Sep 17 00:00:00 2001 From: Devon Loehr <dlo...@google.com> Date: Tue, 22 Jul 2025 14:57:34 +0000 Subject: [PATCH 2/4] Enable only for special case list --- llvm/include/llvm/Support/GlobPattern.h | 9 +++++++-- llvm/lib/Support/GlobPattern.cpp | 12 +++++++----- llvm/lib/Support/SpecialCaseList.cpp | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index af92c63331282..2729ba9a56649 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -56,8 +56,10 @@ class GlobPattern { /// \param MaxSubPatterns if provided limit the number of allowed subpatterns /// created from expanding braces otherwise disable /// brace expansion + /// \param IsSlashAgnostic whether to treat '/' as matching '\\' as well LLVM_ABI static Expected<GlobPattern> - create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {}); + create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {}, + bool IsSlashAgnostic = false); /// \returns \p true if \p S matches this glob pattern LLVM_ABI bool match(StringRef S) const; @@ -76,7 +78,9 @@ class GlobPattern { struct SubGlobPattern { /// \param Pat the pattern to match against - LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat); + /// \param SlashAgnostic whether to treat '/' as matching '\\' as well + LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat, + bool SlashAgnostic); /// \returns \p true if \p S matches this glob pattern LLVM_ABI bool match(StringRef S) const; StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); } @@ -88,6 +92,7 @@ class GlobPattern { }; SmallVector<Bracket, 0> Brackets; SmallVector<char, 0> Pat; + bool IsSlashAgnostic; }; SmallVector<SubGlobPattern, 1> SubGlobs; }; diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp index 26b3724863ee8..4aa30a81c3fbf 100644 --- a/llvm/lib/Support/GlobPattern.cpp +++ b/llvm/lib/Support/GlobPattern.cpp @@ -132,8 +132,9 @@ parseBraceExpansions(StringRef S, std::optional<size_t> MaxSubPatterns) { return std::move(SubPatterns); } -Expected<GlobPattern> -GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) { +Expected<GlobPattern> GlobPattern::create(StringRef S, + std::optional<size_t> MaxSubPatterns, + bool IsSlashAgnostic) { GlobPattern Pat; // Store the prefix that does not contain any metacharacter. @@ -147,7 +148,7 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) { if (auto Err = parseBraceExpansions(S, MaxSubPatterns).moveInto(SubPats)) return std::move(Err); for (StringRef SubPat : SubPats) { - auto SubGlobOrErr = SubGlobPattern::create(SubPat); + auto SubGlobOrErr = SubGlobPattern::create(SubPat, IsSlashAgnostic); if (!SubGlobOrErr) return SubGlobOrErr.takeError(); Pat.SubGlobs.push_back(*SubGlobOrErr); @@ -157,8 +158,9 @@ GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) { } Expected<GlobPattern::SubGlobPattern> -GlobPattern::SubGlobPattern::create(StringRef S) { +GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) { SubGlobPattern Pat; + Pat.IsSlashAgnostic = SlashAgnostic; // Parse brackets. Pat.Pat.assign(S.begin(), S.end()); @@ -231,7 +233,7 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const { ++S; continue; } - } else if (*P == '/' && (*S == '/' || *S == '\\')) { + } else if (IsSlashAgnostic && *P == '/' && (*S == '/' || *S == '\\')) { ++P; ++S; continue; diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp index 8d4e043bc1c9f..c597f03188507 100644 --- a/llvm/lib/Support/SpecialCaseList.cpp +++ b/llvm/lib/Support/SpecialCaseList.cpp @@ -59,7 +59,8 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber, Glob->LineNo = LineNumber; // We must be sure to use the string in `Glob` rather than the provided // reference which could be destroyed before match() is called - if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024) + if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024, + /*IsSlashAgnostic=*/true) .moveInto(Glob->Pattern)) return Err; Globs.push_back(std::move(Glob)); >From d3d4c664e3bc958dc6f5e5597d130f478f5b7f29 Mon Sep 17 00:00:00 2001 From: Devon Loehr <dlo...@google.com> Date: Fri, 5 Sep 2025 16:48:17 +0000 Subject: [PATCH 3/4] Enable only on windows --- clang/docs/SanitizerSpecialCaseList.rst | 2 +- clang/unittests/Basic/DiagnosticTest.cpp | 3 +++ llvm/docs/ReleaseNotes.md | 4 ++-- llvm/include/llvm/Support/GlobPattern.h | 3 ++- llvm/lib/Support/SpecialCaseList.cpp | 6 +++++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index f2a04dc9adcf1..e14b654536b8a 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -174,7 +174,7 @@ tool-specific docs. # Lines starting with # are ignored. # Turn off checks for the source file # Entries without sections are placed into [*] and apply to all sanitizers - # "/" matches both windows and unix path separators ("/" and "\") + # On windows, "/" matches both styles of path separator ("/" and "\") src:path/to/source/file.c src:*/source/file.c # Turn off checks for this main file, including files included by it. diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp index a6557b1e35c4b..7e9653bdd3c7e 100644 --- a/clang/unittests/Basic/DiagnosticTest.cpp +++ b/clang/unittests/Basic/DiagnosticTest.cpp @@ -361,6 +361,8 @@ TEST_F(SuppressionMappingTest, ParsingRespectsOtherWarningOpts) { EXPECT_THAT(diags(), IsEmpty()); } +#ifdef _WIN32 +// We're only slash-agnostic on windows hosts TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) { llvm::StringLiteral SuppressionMappingFile = R"( [unused] @@ -383,4 +385,5 @@ TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) { EXPECT_FALSE(Diags.isSuppressedViaMapping( diag::warn_unused_function, locForFile(R"(clang/lib/Sema/foo.h)"))); } +#endif } // namespace diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index d677ce865dc69..1f7b96582e701 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -165,9 +165,9 @@ Changes to BOLT Changes to Sanitizers --------------------- -* The [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format) +* On windows hosts, the [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format) now treats forward slashes as either a forward or a backslash, to handle - paths with mixed unix and window styles. + paths with mixed unix and windows styles. Other Changes ------------- diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index 2729ba9a56649..4abd6b1874593 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -35,7 +35,8 @@ namespace llvm { /// expansions are not supported. If \p MaxSubPatterns is empty then /// brace expansions are not supported and characters `{,}` are treated as /// literals. -/// * `/` matches both unix and windows path separators: `/` and `\`. +/// * If IsSlashAgnostic is passed, `/` matches both unix and windows path +/// separators: `/` and `\`. /// * `\` escapes the next character so it is treated as a literal. /// /// Some known edge cases are: diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp index c597f03188507..89ec193e1991c 100644 --- a/llvm/lib/Support/SpecialCaseList.cpp +++ b/llvm/lib/Support/SpecialCaseList.cpp @@ -18,6 +18,8 @@ #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" #include <stdio.h> #include <string> #include <system_error> @@ -57,10 +59,12 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber, auto Glob = std::make_unique<Matcher::Glob>(); Glob->Name = Pattern.str(); Glob->LineNo = LineNumber; + // Backslashes are valid in posix-style filenames. + bool IsSlashAgnostic = Triple(sys::getDefaultTargetTriple()).isOSWindows(); // We must be sure to use the string in `Glob` rather than the provided // reference which could be destroyed before match() is called if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024, - /*IsSlashAgnostic=*/true) + /*IsSlashAgnostic=*/IsSlashAgnostic) .moveInto(Glob->Pattern)) return Err; Globs.push_back(std::move(Glob)); >From e3f8b08fab7c3a0a05c92080201061ae8cab288d Mon Sep 17 00:00:00 2001 From: Devon Loehr <dlo...@google.com> Date: Mon, 8 Sep 2025 15:00:04 +0000 Subject: [PATCH 4/4] Incorporate review feedback --- clang/docs/SanitizerSpecialCaseList.rst | 2 +- clang/lib/Basic/Diagnostic.cpp | 5 ++++- clang/lib/Basic/SanitizerSpecialCaseList.cpp | 2 +- clang/unittests/Basic/DiagnosticTest.cpp | 12 ++++++----- llvm/docs/ReleaseNotes.md | 4 ++-- llvm/include/llvm/Support/GlobPattern.h | 19 +++++++---------- llvm/include/llvm/Support/SpecialCaseList.h | 5 +++-- llvm/lib/Support/GlobPattern.cpp | 21 +++++++++---------- llvm/lib/Support/SpecialCaseList.cpp | 22 +++++++++++--------- 9 files changed, 48 insertions(+), 44 deletions(-) diff --git a/clang/docs/SanitizerSpecialCaseList.rst b/clang/docs/SanitizerSpecialCaseList.rst index e14b654536b8a..752602c1b3093 100644 --- a/clang/docs/SanitizerSpecialCaseList.rst +++ b/clang/docs/SanitizerSpecialCaseList.rst @@ -174,7 +174,7 @@ tool-specific docs. # Lines starting with # are ignored. # Turn off checks for the source file # Entries without sections are placed into [*] and apply to all sanitizers - # On windows, "/" matches both styles of path separator ("/" and "\") + # On windows, "/" also matches "\" in filenames src:path/to/source/file.c src:*/source/file.c # Turn off checks for this main file, including files included by it. diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index dc3778bbf339c..9dd133cb4c03e 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -622,6 +622,8 @@ bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId, bool WarningsSpecialCaseList::globsMatches( const llvm::StringMap<Matcher> &CategoriesToMatchers, StringRef FilePath) const { + static bool HaveWindowsPathStyle = + llvm::sys::path::is_style_windows(llvm::sys::path::Style::native); StringRef LongestMatch; bool LongestIsPositive = false; for (const auto &Entry : CategoriesToMatchers) { @@ -631,7 +633,8 @@ bool WarningsSpecialCaseList::globsMatches( for (const auto &Glob : Matcher.Globs) { if (Glob->Name.size() < LongestMatch.size()) continue; - if (!Glob->Pattern.match(FilePath)) + if (!Glob->Pattern.match(FilePath, + /*IsSlashAgnostic=*/HaveWindowsPathStyle)) continue; LongestMatch = Glob->Name; LongestIsPositive = IsPositive; diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp index f7bc1d5545d75..4ad35d4d73fdd 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->match(NAME, /*IsFilename=*/false)) \ Mask |= SanitizerKind::ID; #define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID) diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp index 7e9653bdd3c7e..2af86b6a5ef38 100644 --- a/clang/unittests/Basic/DiagnosticTest.cpp +++ b/clang/unittests/Basic/DiagnosticTest.cpp @@ -363,12 +363,13 @@ TEST_F(SuppressionMappingTest, ParsingRespectsOtherWarningOpts) { #ifdef _WIN32 // We're only slash-agnostic on windows hosts -TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) { +TEST_F(SuppressionMappingTest, TreatsFilesAsSlashAgnosticOnWindows) { llvm::StringLiteral SuppressionMappingFile = R"( [unused] src:*clang/* src:*clang/lib/Sema/*=emit - src:*clang/lib\\Sema/foo*)"; + src:*clang/lib\\Sema/foo* + fun:suppress/me)"; Diags.getDiagnosticOptions().DiagnosticSuppressionMappingsFile = "foo.txt"; FS->addFile("foo.txt", /*ModificationTime=*/{}, llvm::MemoryBuffer::getMemBuffer(SuppressionMappingFile)); @@ -376,12 +377,13 @@ TEST_F(SuppressionMappingTest, ForwardSlashMatchesBothDirections) { EXPECT_THAT(diags(), IsEmpty()); EXPECT_TRUE(Diags.isSuppressedViaMapping( - diag::warn_unused_function, locForFile(R"(clang/lib/Basic/foo.h)"))); + diag::warn_unused_function, locForFile(R"(clang/lib/Basic/bar.h)"))); EXPECT_FALSE(Diags.isSuppressedViaMapping( - diag::warn_unused_function, locForFile(R"(clang/lib/Sema\bar.h)"))); + diag::warn_unused_function, locForFile(R"(clang/lib/Sema\baz.h)"))); + + // We require a literal backslash before "Sema" EXPECT_TRUE(Diags.isSuppressedViaMapping( diag::warn_unused_function, locForFile(R"(clang\lib\Sema/foo.h)"))); - // The third pattern requires a literal backslash before Sema EXPECT_FALSE(Diags.isSuppressedViaMapping( diag::warn_unused_function, locForFile(R"(clang/lib/Sema/foo.h)"))); } diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 1f7b96582e701..b530a66b7abc6 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -166,8 +166,8 @@ Changes to Sanitizers --------------------- * On windows hosts, the [sanitizer special case list format](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html#format) - now treats forward slashes as either a forward or a backslash, to handle - paths with mixed unix and windows styles. + now treats forward slashes in filenames as matching either a forward or a + backslash, to accommodate paths with mixed unix and windows styles. Other Changes ------------- diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index 4abd6b1874593..5fd1e0764cc7a 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -35,9 +35,9 @@ namespace llvm { /// expansions are not supported. If \p MaxSubPatterns is empty then /// brace expansions are not supported and characters `{,}` are treated as /// literals. -/// * If IsSlashAgnostic is passed, `/` matches both unix and windows path -/// separators: `/` and `\`. /// * `\` escapes the next character so it is treated as a literal. +/// * If \p IsSlashAgnostic is passed to the match function, then forward +/// slashes `/` also match backslashes `\`. /// /// Some known edge cases are: /// * The literal `]` is allowed as the first character in a character class, @@ -57,12 +57,11 @@ class GlobPattern { /// \param MaxSubPatterns if provided limit the number of allowed subpatterns /// created from expanding braces otherwise disable /// brace expansion - /// \param IsSlashAgnostic whether to treat '/' as matching '\\' as well LLVM_ABI static Expected<GlobPattern> - create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {}, - bool IsSlashAgnostic = false); + create(StringRef Pat, std::optional<size_t> MaxSubPatterns = {}); + /// \param IsSlashAgnostic whether to treat '/' as also matching '\' /// \returns \p true if \p S matches this glob pattern - LLVM_ABI bool match(StringRef S) const; + LLVM_ABI bool match(StringRef S, bool IsSlashAgnostic = false) const; // Returns true for glob pattern "*". Can be used to avoid expensive // preparation/acquisition of the input for match(). @@ -79,11 +78,10 @@ class GlobPattern { struct SubGlobPattern { /// \param Pat the pattern to match against - /// \param SlashAgnostic whether to treat '/' as matching '\\' as well - LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat, - bool SlashAgnostic); + LLVM_ABI static Expected<SubGlobPattern> create(StringRef Pat); + /// \param IsSlashAgnostic whether to treat '/' as also matching '\' /// \returns \p true if \p S matches this glob pattern - LLVM_ABI bool match(StringRef S) const; + LLVM_ABI bool match(StringRef S, bool IsSlashAgnostic) const; StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); } // Brackets with their end position and matched bytes. @@ -93,7 +91,6 @@ class GlobPattern { }; SmallVector<Bracket, 0> Brackets; SmallVector<char, 0> Pat; - bool IsSlashAgnostic; }; SmallVector<SubGlobPattern, 1> SubGlobs; }; diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h index 22a62eac9e01a..951f27eed8ee8 100644 --- a/llvm/include/llvm/Support/SpecialCaseList.h +++ b/llvm/include/llvm/Support/SpecialCaseList.h @@ -124,8 +124,9 @@ class SpecialCaseList { 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; + // On windows, treat '/' as also matching '\' in filenames when using globs. + // Returns zero if no match is found + LLVM_ABI unsigned match(StringRef Query, bool IsFilename) const; struct Glob { std::string Name; diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp index 4aa30a81c3fbf..578c0dd0760d2 100644 --- a/llvm/lib/Support/GlobPattern.cpp +++ b/llvm/lib/Support/GlobPattern.cpp @@ -132,9 +132,8 @@ parseBraceExpansions(StringRef S, std::optional<size_t> MaxSubPatterns) { return std::move(SubPatterns); } -Expected<GlobPattern> GlobPattern::create(StringRef S, - std::optional<size_t> MaxSubPatterns, - bool IsSlashAgnostic) { +Expected<GlobPattern> +GlobPattern::create(StringRef S, std::optional<size_t> MaxSubPatterns) { GlobPattern Pat; // Store the prefix that does not contain any metacharacter. @@ -148,7 +147,7 @@ Expected<GlobPattern> GlobPattern::create(StringRef S, if (auto Err = parseBraceExpansions(S, MaxSubPatterns).moveInto(SubPats)) return std::move(Err); for (StringRef SubPat : SubPats) { - auto SubGlobOrErr = SubGlobPattern::create(SubPat, IsSlashAgnostic); + auto SubGlobOrErr = SubGlobPattern::create(SubPat); if (!SubGlobOrErr) return SubGlobOrErr.takeError(); Pat.SubGlobs.push_back(*SubGlobOrErr); @@ -158,9 +157,8 @@ Expected<GlobPattern> GlobPattern::create(StringRef S, } Expected<GlobPattern::SubGlobPattern> -GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) { +GlobPattern::SubGlobPattern::create(StringRef S) { SubGlobPattern Pat; - Pat.IsSlashAgnostic = SlashAgnostic; // Parse brackets. Pat.Pat.assign(S.begin(), S.end()); @@ -192,21 +190,22 @@ GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) { return Pat; } -bool GlobPattern::match(StringRef S) const { +bool GlobPattern::match(StringRef S, bool IsSlashAgnostic) const { if (!S.consume_front(Prefix)) return false; if (SubGlobs.empty() && S.empty()) return true; for (auto &Glob : SubGlobs) - if (Glob.match(S)) + if (Glob.match(S, IsSlashAgnostic)) return true; return false; } // Factor the pattern into segments split by '*'. The segment is matched -// sequentianlly by finding the first occurrence past the end of the previous +// sequentially by finding the first occurrence past the end of the previous // match. -bool GlobPattern::SubGlobPattern::match(StringRef Str) const { +bool GlobPattern::SubGlobPattern::match(StringRef Str, + bool IsSlashAgnostic) const { const char *P = Pat.data(), *SegmentBegin = nullptr, *S = Str.data(), *SavedS = S; const char *const PEnd = P + Pat.size(), *const End = S + Str.size(); @@ -233,7 +232,7 @@ bool GlobPattern::SubGlobPattern::match(StringRef Str) const { ++S; continue; } - } else if (IsSlashAgnostic && *P == '/' && (*S == '/' || *S == '\\')) { + } else if (IsSlashAgnostic && *P == '/' && *S == '\\') { ++P; ++S; continue; diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp index 89ec193e1991c..6e569768e2856 100644 --- a/llvm/lib/Support/SpecialCaseList.cpp +++ b/llvm/lib/Support/SpecialCaseList.cpp @@ -17,9 +17,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" -#include "llvm/TargetParser/Host.h" -#include "llvm/TargetParser/Triple.h" #include <stdio.h> #include <string> #include <system_error> @@ -59,21 +58,22 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber, auto Glob = std::make_unique<Matcher::Glob>(); Glob->Name = Pattern.str(); Glob->LineNo = LineNumber; - // Backslashes are valid in posix-style filenames. - bool IsSlashAgnostic = Triple(sys::getDefaultTargetTriple()).isOSWindows(); // We must be sure to use the string in `Glob` rather than the provided // reference which could be destroyed before match() is called - if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024, - /*IsSlashAgnostic=*/IsSlashAgnostic) + if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024) .moveInto(Glob->Pattern)) return Err; Globs.push_back(std::move(Glob)); return Error::success(); } -unsigned SpecialCaseList::Matcher::match(StringRef Query) const { +unsigned SpecialCaseList::Matcher::match(StringRef Query, + bool IsFilename) const { + static bool HaveWindowsPathStyle = + llvm::sys::path::is_style_windows(llvm::sys::path::Style::native); for (const auto &Glob : reverse(Globs)) - if (Glob->Pattern.match(Query)) + if (Glob->Pattern.match(Query, /*IsSlashAgnostic=*/(HaveWindowsPathStyle && + IsFilename))) return Glob->LineNo; for (const auto &[Regex, LineNumber] : reverse(RegExes)) if (Regex->match(Query)) @@ -223,7 +223,8 @@ 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)) { + bool IsFilename = Prefix == "src" || Prefix == "mainfile"; + if (S.SectionMatcher->match(Section, IsFilename)) { unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category); if (Blame) return {S.FileIdx, Blame}; @@ -242,7 +243,8 @@ unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries, if (II == I->second.end()) return 0; - return II->getValue().match(Query); + bool IsFilename = Prefix == "src" || Prefix == "mainfile"; + return II->getValue().match(Query, IsFilename); } } // namespace llvm _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits