Skip to content

Commit 1b20f4c

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.6
2 parents b98ac06 + ead4c27 commit 1b20f4c

File tree

8 files changed

+115
-91
lines changed

8 files changed

+115
-91
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: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <memory>
2020
#include <string>
2121
#include <utility>
22+
#include <variant>
2223
#include <vector>
2324

2425
namespace llvm {
@@ -118,15 +119,20 @@ class SpecialCaseList {
118119
SpecialCaseList(SpecialCaseList const &) = delete;
119120
SpecialCaseList &operator=(SpecialCaseList const &) = delete;
120121

121-
/// Represents a set of globs and their line numbers
122-
class Matcher {
122+
// Lagacy v1 matcher.
123+
class RegexMatcher {
124+
public:
125+
LLVM_ABI unsigned match(StringRef Query) const;
126+
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
127+
std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes;
128+
};
129+
130+
class GlobMatcher {
123131
public:
124-
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber,
125-
bool UseRegex);
126132
// Returns the line number in the source file that this query matches to.
127133
// Returns zero if no match is found.
128134
LLVM_ABI unsigned match(StringRef Query) const;
129-
135+
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
130136
struct Glob {
131137
std::string Name;
132138
unsigned LineNo;
@@ -137,17 +143,33 @@ class SpecialCaseList {
137143
Glob() = default;
138144
};
139145

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

144164
using SectionEntries = StringMap<StringMap<Matcher>>;
145165

146166
struct Section {
147-
Section(StringRef Str, unsigned FileIdx)
148-
: SectionStr(Str), FileIdx(FileIdx) {};
167+
Section(StringRef Str, unsigned FileIdx, bool UseGlobs)
168+
: SectionMatcher(UseGlobs), SectionStr(Str), FileIdx(FileIdx) {};
169+
170+
Section(Section &&) = default;
149171

150-
std::unique_ptr<Matcher> SectionMatcher = std::make_unique<Matcher>();
172+
Matcher SectionMatcher;
151173
SectionEntries Entries;
152174
std::string SectionStr;
153175
unsigned FileIdx;
@@ -157,7 +179,7 @@ class SpecialCaseList {
157179

158180
LLVM_ABI Expected<Section *> addSection(StringRef SectionStr,
159181
unsigned FileIdx, unsigned LineNo,
160-
bool UseGlobs = true);
182+
bool UseGlobs);
161183

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

llvm/lib/Support/SpecialCaseList.cpp

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,36 +25,48 @@
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+
}
34+
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+
}
41+
42+
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
43+
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);
4249

43-
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
50+
RegExes.emplace_back(
51+
std::make_pair(std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
4452

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);
53+
return Error::success();
54+
}
5055

51-
RegExes.emplace_back(std::make_pair(
52-
std::make_unique<Regex>(std::move(CheckRE)), LineNumber));
56+
unsigned SpecialCaseList::RegexMatcher::match(StringRef Query) const {
57+
for (const auto &[Regex, LineNumber] : reverse(RegExes))
58+
if (Regex->match(Query))
59+
return LineNumber;
60+
return 0;
61+
}
5362

54-
return Error::success();
63+
Error SpecialCaseList::GlobMatcher::insert(StringRef Pattern,
64+
unsigned LineNumber) {
65+
if (Pattern.empty()) {
66+
return createStringError(errc::invalid_argument, "Supplied glob was blank");
5567
}
5668

57-
auto Glob = std::make_unique<Matcher::Glob>();
69+
auto Glob = std::make_unique<GlobMatcher::Glob>();
5870
Glob->Name = Pattern.str();
5971
Glob->LineNo = LineNumber;
6072
// We must be sure to use the string in `Glob` rather than the provided
@@ -66,16 +78,28 @@ Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
6678
return Error::success();
6779
}
6880

69-
unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
81+
unsigned SpecialCaseList::GlobMatcher::match(StringRef Query) const {
7082
for (const auto &Glob : reverse(Globs))
7183
if (Glob->Pattern.match(Query))
7284
return Glob->LineNo;
73-
for (const auto &[Regex, LineNumber] : reverse(RegExes))
74-
if (Regex->match(Query))
75-
return LineNumber;
7685
return 0;
7786
}
7887

88+
SpecialCaseList::Matcher::Matcher(bool UseGlobs) {
89+
if (UseGlobs)
90+
M.emplace<GlobMatcher>();
91+
else
92+
M.emplace<RegexMatcher>();
93+
}
94+
95+
unsigned SpecialCaseList::Matcher::match(StringRef Query) const {
96+
return std::visit([&](auto &V) { return V.match(Query); }, M);
97+
}
98+
99+
Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber) {
100+
return std::visit([&](auto &V) { return V.insert(Pattern, LineNumber); }, M);
101+
}
102+
79103
// TODO: Refactor this to return Expected<...>
80104
std::unique_ptr<SpecialCaseList>
81105
SpecialCaseList::create(const std::vector<std::string> &Paths,
@@ -132,10 +156,10 @@ bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
132156
Expected<SpecialCaseList::Section *>
133157
SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
134158
unsigned LineNo, bool UseGlobs) {
135-
Sections.emplace_back(SectionStr, FileNo);
159+
Sections.emplace_back(SectionStr, FileNo, UseGlobs);
136160
auto &Section = Sections.back();
137161

138-
if (auto Err = Section.SectionMatcher->insert(SectionStr, LineNo, UseGlobs)) {
162+
if (auto Err = Section.SectionMatcher.insert(SectionStr, LineNo)) {
139163
return createStringError(errc::invalid_argument,
140164
"malformed section at line " + Twine(LineNo) +
141165
": '" + SectionStr +
@@ -148,7 +172,7 @@ SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
148172
bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
149173
std::string &Error) {
150174
Section *CurrentSection;
151-
if (auto Err = addSection("*", FileIdx, 1).moveInto(CurrentSection)) {
175+
if (auto Err = addSection("*", FileIdx, 1, true).moveInto(CurrentSection)) {
152176
Error = toString(std::move(Err));
153177
return false;
154178
}
@@ -194,8 +218,9 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
194218
}
195219

196220
auto [Pattern, Category] = Postfix.split("=");
197-
auto &Entry = CurrentSection->Entries[Prefix][Category];
198-
if (auto Err = Entry.insert(Pattern, LineNo, UseGlobs)) {
221+
auto [It, _] =
222+
CurrentSection->Entries[Prefix].try_emplace(Category, UseGlobs);
223+
if (auto Err = It->second.insert(Pattern, LineNo)) {
199224
Error =
200225
(Twine("malformed ") + (UseGlobs ? "glob" : "regex") + " in line " +
201226
Twine(LineNo) + ": '" + Pattern + "': " + toString(std::move(Err)))
@@ -218,7 +243,7 @@ std::pair<unsigned, unsigned>
218243
SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
219244
StringRef Query, StringRef Category) const {
220245
for (const auto &S : reverse(Sections)) {
221-
if (S.SectionMatcher->match(Section)) {
246+
if (S.SectionMatcher.match(Section)) {
222247
unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category);
223248
if (Blame)
224249
return {S.FileIdx, Blame};

0 commit comments

Comments
 (0)