Skip to content

Commit 155f4f9

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6
2 parents b98ac06 + fd2dad1 commit 155f4f9

File tree

8 files changed

+124
-105
lines changed

8 files changed

+124
-105
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Potentially Breaking Changes
6969
call the member ``operator delete`` instead of the expected global
7070
delete operator. The old behavior is retained under ``-fclang-abi-compat=21``
7171
flag.
72+
- Clang warning suppressions file, ``--warning-suppression-mappings=``, now will
73+
use the last matching entry instead of the longest one.
7274

7375
C/C++ Language Potentially Breaking Changes
7476
-------------------------------------------

clang/docs/WarningSuppressionMappings.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Format
6363
Warning suppression mappings uses the same format as
6464
:doc:`SanitizerSpecialCaseList`.
6565

66-
Sections describe which diagnostic group's behaviour to change, e.g.
66+
Sections describe which diagnostic group's behavior to change, e.g.
6767
``[unused]``. When a diagnostic is matched by multiple sections, the latest
6868
section takes precedence.
6969

@@ -76,7 +76,7 @@ Source files are matched against these globs either:
7676
- as paths relative to the current working directory
7777
- as absolute paths.
7878

79-
When a source file matches multiple globs in a section, the longest one takes
79+
When a source file matches multiple globs in a section, the last one takes
8080
precedence.
8181

8282
.. code-block:: bash

clang/include/clang/Basic/Diagnostic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
971971
/// diagnostics in specific files.
972972
/// Mapping file is expected to be a special case list with sections denoting
973973
/// diagnostic groups and `src` entries for globs to suppress. `emit` category
974-
/// can be used to disable suppression. Longest glob that matches a filepath
974+
/// can be used to disable suppression. THe last glob that matches a filepath
975975
/// takes precedence. For example:
976976
/// [unused]
977977
/// src:clang/*

clang/lib/Basic/Diagnostic.cpp

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,6 @@ class WarningsSpecialCaseList : public llvm::SpecialCaseList {
517517
const SourceManager &SM) const;
518518

519519
private:
520-
// Find the longest glob pattern that matches FilePath amongst
521-
// CategoriesToMatchers, return true iff the match exists and belongs to a
522-
// positive category.
523-
bool globsMatches(const llvm::StringMap<Matcher> &CategoriesToMatchers,
524-
StringRef FilePath) const;
525-
526520
llvm::DenseMap<diag::kind, const Section *> DiagToSection;
527521
};
528522
} // namespace
@@ -584,43 +578,26 @@ void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
584578
bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
585579
SourceLocation DiagLoc,
586580
const SourceManager &SM) const {
581+
PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc);
582+
if (!PLoc.isValid())
583+
return false;
587584
const Section *DiagSection = DiagToSection.lookup(DiagId);
588585
if (!DiagSection)
589586
return false;
590-
const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
591-
auto SrcEntriesIt = EntityTypeToCategories.find("src");
592-
if (SrcEntriesIt == EntityTypeToCategories.end())
587+
588+
StringRef F = llvm::sys::path::remove_leading_dotslash(PLoc.getFilename());
589+
590+
unsigned SuppressLineNo =
591+
llvm::SpecialCaseList::inSectionBlame(DiagSection->Entries, "src", F, "");
592+
if (!SuppressLineNo)
593593
return false;
594-
const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
595-
SrcEntriesIt->getValue();
596-
// We also use presumed locations here to improve reproducibility for
597-
// preprocessed inputs.
598-
if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())
599-
return globsMatches(
600-
CategoriesToMatchers,
601-
llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));
602-
return false;
603-
}
604594

605-
bool WarningsSpecialCaseList::globsMatches(
606-
const llvm::StringMap<Matcher> &CategoriesToMatchers,
607-
StringRef FilePath) const {
608-
StringRef LongestMatch;
609-
bool LongestIsPositive = false;
610-
for (const auto &Entry : CategoriesToMatchers) {
611-
StringRef Category = Entry.getKey();
612-
const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();
613-
bool IsPositive = Category != "emit";
614-
for (const auto &Glob : Matcher.Globs) {
615-
if (Glob->Name.size() < LongestMatch.size())
616-
continue;
617-
if (!Glob->Pattern.match(FilePath))
618-
continue;
619-
LongestMatch = Glob->Name;
620-
LongestIsPositive = IsPositive;
621-
}
622-
}
623-
return LongestIsPositive;
595+
unsigned EmitLineNo = llvm::SpecialCaseList::inSectionBlame(
596+
DiagSection->Entries, "src", F, "emit");
597+
if (!EmitLineNo)
598+
return true;
599+
600+
return SuppressLineNo > EmitLineNo;
624601
}
625602

626603
bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId,

clang/lib/Basic/SanitizerSpecialCaseList.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void SanitizerSpecialCaseList::createSanitizerSections() {
4242
SanitizerMask Mask;
4343

4444
#define SANITIZER(NAME, ID) \
45-
if (S.SectionMatcher->match(NAME)) \
45+
if (S.SectionMatcher.match(NAME)) \
4646
Mask |= SanitizerKind::ID;
4747
#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)
4848

clang/unittests/Basic/DiagnosticTest.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ TEST_F(SuppressionMappingTest, EmitCategoryIsExcluded) {
294294
locForFile("foo.cpp")));
295295
}
296296

297-
TEST_F(SuppressionMappingTest, LongestMatchWins) {
297+
TEST_F(SuppressionMappingTest, LastMatchWins) {
298298
llvm::StringLiteral SuppressionMappingFile = R"(
299299
[unused]
300300
src:*clang/*
@@ -327,10 +327,8 @@ TEST_F(SuppressionMappingTest, LongShortMatch) {
327327

328328
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
329329
locForFile("test/t1.cpp")));
330-
331-
// FIXME: This is confusing.
332-
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
333-
locForFile("lld/test/t2.cpp")));
330+
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
331+
locForFile("lld/test/t2.cpp")));
334332
}
335333

336334
TEST_F(SuppressionMappingTest, ShortLongMatch) {

llvm/include/llvm/Support/SpecialCaseList.h

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
#define LLVM_SUPPORT_SPECIALCASELIST_H
1414

1515
#include "llvm/ADT/StringMap.h"
16+
#include "llvm/Support/Allocator.h"
1617
#include "llvm/Support/Compiler.h"
1718
#include "llvm/Support/GlobPattern.h"
1819
#include "llvm/Support/Regex.h"
1920
#include <memory>
2021
#include <string>
2122
#include <utility>
23+
#include <variant>
2224
#include <vector>
2325

2426
namespace llvm {
@@ -118,46 +120,65 @@ class SpecialCaseList {
118120
SpecialCaseList(SpecialCaseList const &) = delete;
119121
SpecialCaseList &operator=(SpecialCaseList const &) = delete;
120122

121-
/// Represents a set of globs and their line numbers
122-
class Matcher {
123+
// Lagacy v1 matcher.
124+
class RegexMatcher {
125+
public:
126+
LLVM_ABI unsigned match(StringRef Query) const;
127+
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
128+
std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes;
129+
};
130+
131+
class GlobMatcher {
123132
public:
124-
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber,
125-
bool UseRegex);
126133
// Returns the line number in the source file that this query matches to.
127134
// Returns zero if no match is found.
128135
LLVM_ABI unsigned match(StringRef Query) const;
129-
136+
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
130137
struct Glob {
131-
std::string Name;
138+
Glob(unsigned LineNo, GlobPattern &&Pattern)
139+
: LineNo(LineNo), Pattern(std::move(Pattern)) {}
132140
unsigned LineNo;
133141
GlobPattern Pattern;
134-
// neither copyable nor movable because GlobPattern contains
135-
// Glob::StringRef that points to Glob::Name.
136-
Glob(Glob &&) = delete;
137-
Glob() = default;
138142
};
139143

140-
std::vector<std::unique_ptr<Matcher::Glob>> Globs;
141-
std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes;
144+
std::vector<GlobMatcher::Glob> Globs;
145+
};
146+
147+
/// Represents a set of globs and their line numbers
148+
class Matcher {
149+
public:
150+
LLVM_ABI explicit Matcher(bool UseGlobs);
151+
// Returns the line number in the source file that this query matches to.
152+
// Returns zero if no match is found.
153+
LLVM_ABI unsigned match(StringRef Query) const;
154+
155+
private:
156+
friend class SpecialCaseList;
157+
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
158+
159+
std::variant<RegexMatcher, GlobMatcher> M;
142160
};
143161

144162
using SectionEntries = StringMap<StringMap<Matcher>>;
145163

146164
struct Section {
147-
Section(StringRef Str, unsigned FileIdx)
148-
: SectionStr(Str), FileIdx(FileIdx) {};
165+
Section(StringRef Str, unsigned FileIdx, bool UseGlobs)
166+
: SectionMatcher(UseGlobs), SectionStr(Str), FileIdx(FileIdx) {};
167+
168+
Section(Section &&) = default;
149169

150-
std::unique_ptr<Matcher> SectionMatcher = std::make_unique<Matcher>();
170+
Matcher SectionMatcher;
151171
SectionEntries Entries;
152172
std::string SectionStr;
153173
unsigned FileIdx;
154174
};
155175

176+
BumpPtrAllocator StrAlloc;
156177
std::vector<Section> Sections;
157178

158179
LLVM_ABI Expected<Section *> addSection(StringRef SectionStr,
159180
unsigned FileIdx, unsigned LineNo,
160-
bool UseGlobs = true);
181+
bool UseGlobs);
161182

162183
/// Parses just-constructed SpecialCaseList entries from a memory buffer.
163184
LLVM_ABI bool parse(unsigned FileIdx, const MemoryBuffer *MB,

llvm/lib/Support/SpecialCaseList.cpp

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,57 +25,75 @@
2525

2626
namespace llvm {
2727

28-
Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
29-
bool UseGlobs) {
30-
if (Pattern.empty())
28+
Error SpecialCaseList::RegexMatcher::insert(StringRef Pattern,
29+
unsigned LineNumber) {
30+
if (Pattern.empty()) {
3131
return createStringError(errc::invalid_argument,
32-
Twine("Supplied ") +
33-
(UseGlobs ? "glob" : "regex") + " was blank");
34-
35-
if (!UseGlobs) {
36-
// Replace * with .*
37-
auto Regexp = Pattern.str();
38-
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
39-
pos += strlen(".*")) {
40-
Regexp.replace(pos, strlen("*"), ".*");
41-
}
32+
"Supplied regex was blank");
33+
}
4234

43-
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
35+
// Replace * with .*
36+
auto Regexp = Pattern.str();
37+
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
38+
pos += strlen(".*")) {
39+
Regexp.replace(pos, strlen("*"), ".*");
40+
}
4441

45-
// Check that the regexp is valid.
46-
Regex CheckRE(Regexp);
47-
std::string REError;
48-
if (!CheckRE.isValid(REError))
49-
return createStringError(errc::invalid_argument, REError);
42+
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
5043

51-
RegExes.emplace_back(std::make_pair(
52-
std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
44+
// Check that the regexp is valid.
45+
Regex CheckRE(Regexp);
46+
std::string REError;
47+
if (!CheckRE.isValid(REError))
48+
return createStringError(errc::invalid_argument, REError);
5349

54-
return Error::success();
55-
}
50+
RegExes.emplace_back(
51+
std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
5652

57-
auto Glob = std::make_unique<Matcher::Glob>();
58-
Glob->Name = Pattern.str();
59-
Glob->LineNo = LineNumber;
60-
// We must be sure to use the string in `Glob` rather than the provided
61-
// reference which could be destroyed before match() is called
62-
if (auto Err = GlobPattern::create(Glob->Name, /*MaxSubPatterns=*/1024)
63-
.moveInto(Glob->Pattern))
64-
return Err;
65-
Globs.push_back(std::move(Glob));
6653
return Error::success();
6754
}
6855

69-
unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
70-
for (const auto &Glob : reverse(Globs))
71-
if (Glob->Pattern.match(Query))
72-
return Glob->LineNo;
56+
unsigned SpecialCaseList::RegexMatcher::match(StringRef Query) const {
7357
for (const auto &[Regex, LineNumber] : reverse(RegExes))
7458
if (Regex->match(Query))
7559
return LineNumber;
7660
return 0;
7761
}
7862

63+
Error SpecialCaseList::GlobMatcher::insert(StringRef Pattern,
64+
unsigned LineNumber) {
65+
if (Pattern.empty())
66+
return createStringError(errc::invalid_argument, "Supplied glob was blank");
67+
68+
auto Res = GlobPattern::create(Pattern, /*MaxSubPatterns=*/1024);
69+
if (auto Err = Res.takeError())
70+
return Err;
71+
Globs.emplace_back(LineNumber, std::move(Res.get()));
72+
return Error::success();
73+
}
74+
75+
unsigned SpecialCaseList::GlobMatcher::match(StringRef Query) const {
76+
for (const auto &Glob : reverse(Globs))
77+
if (Glob.Pattern.match(Query))
78+
return Glob.LineNo;
79+
return 0;
80+
}
81+
82+
SpecialCaseList::Matcher::Matcher(bool UseGlobs) {
83+
if (UseGlobs)
84+
M.emplace<GlobMatcher>();
85+
else
86+
M.emplace<RegexMatcher>();
87+
}
88+
89+
unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
90+
return std::visit([&](auto &V) { return V.match(Query); }, M);
91+
}
92+
93+
Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber) {
94+
return std::visit([&](auto &V) { return V.insert(Pattern, LineNumber); }, M);
95+
}
96+
7997
// TODO: Refactor this to return Expected<...>
8098
std::unique_ptr<SpecialCaseList>
8199
SpecialCaseList::create(const std::vector<std::string> &Paths,
@@ -132,10 +150,11 @@ bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
132150
Expected<SpecialCaseList::Section *>
133151
SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
134152
unsigned LineNo, bool UseGlobs) {
135-
Sections.emplace_back(SectionStr, FileNo);
153+
Sections.emplace_back(SectionStr, FileNo, UseGlobs);
136154
auto &Section = Sections.back();
137155

138-
if (auto Err = Section.SectionMatcher->insert(SectionStr, LineNo, UseGlobs)) {
156+
SectionStr = SectionStr.copy(StrAlloc);
157+
if (auto Err = Section.SectionMatcher.insert(SectionStr, LineNo)) {
139158
return createStringError(errc::invalid_argument,
140159
"malformed section at line " + Twine(LineNo) +
141160
": '" + SectionStr +
@@ -148,7 +167,7 @@ SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
148167
bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
149168
std::string &Error) {
150169
Section *CurrentSection;
151-
if (auto Err = addSection("*", FileIdx, 1).moveInto(CurrentSection)) {
170+
if (auto Err = addSection("*", FileIdx, 1, true).moveInto(CurrentSection)) {
152171
Error = toString(std::move(Err));
153172
return false;
154173
}
@@ -194,8 +213,10 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
194213
}
195214

196215
auto [Pattern, Category] = Postfix.split("=");
197-
auto &Entry = CurrentSection->Entries[Prefix][Category];
198-
if (auto Err = Entry.insert(Pattern, LineNo, UseGlobs)) {
216+
auto [It, _] =
217+
CurrentSection->Entries[Prefix].try_emplace(Category, UseGlobs);
218+
Pattern = Pattern.copy(StrAlloc);
219+
if (auto Err = It->second.insert(Pattern, LineNo)) {
199220
Error =
200221
(Twine("malformed ") + (UseGlobs ? "glob" : "regex") + " in line " +
201222
Twine(LineNo) + ": '" + Pattern + "': " + toString(std::move(Err)))
@@ -218,7 +239,7 @@ std::pair<unsigned, unsigned>
218239
SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
219240
StringRef Query, StringRef Category) const {
220241
for (const auto &S : reverse(Sections)) {
221-
if (S.SectionMatcher->match(Section)) {
242+
if (S.SectionMatcher.match(Section)) {
222243
unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category);
223244
if (Blame)
224245
return {S.FileIdx, Blame};

0 commit comments

Comments
 (0)