Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 14 additions & 39 deletions clang/lib/Basic/Diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,6 @@ class WarningsSpecialCaseList : public llvm::SpecialCaseList {
const SourceManager &SM) const;

private:
// Find the longest glob pattern that matches FilePath amongst
// CategoriesToMatchers, return true iff the match exists and belongs to a
// positive category.
bool globsMatches(const llvm::StringMap<Matcher> &CategoriesToMatchers,
StringRef FilePath) const;

llvm::DenseMap<diag::kind, const Section *> DiagToSection;
};
} // namespace
Expand All @@ -538,7 +532,7 @@ WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,

void WarningsSpecialCaseList::processSections(DiagnosticsEngine &Diags) {
static constexpr auto WarningFlavor = clang::diag::Flavor::WarningOrError;
for (const auto &SectionEntry : Sections) {
for (const auto &SectionEntry : sections()) {
StringRef DiagGroup = SectionEntry.SectionStr;
if (DiagGroup == "*") {
// Drop the default section introduced by special case list, we only
Expand Down Expand Up @@ -584,43 +578,24 @@ void DiagnosticsEngine::setDiagSuppressionMapping(llvm::MemoryBuffer &Input) {
bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,
SourceLocation DiagLoc,
const SourceManager &SM) const {
PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc);
if (!PLoc.isValid())
return false;
const Section *DiagSection = DiagToSection.lookup(DiagId);
if (!DiagSection)
return false;
const SectionEntries &EntityTypeToCategories = DiagSection->Entries;
auto SrcEntriesIt = EntityTypeToCategories.find("src");
if (SrcEntriesIt == EntityTypeToCategories.end())

StringRef F = llvm::sys::path::remove_leading_dotslash(PLoc.getFilename());

StringRef LongestSup = DiagSection->getLongestMatch("src", F, "");
if (LongestSup.empty())
return false;
const llvm::StringMap<llvm::SpecialCaseList::Matcher> &CategoriesToMatchers =
SrcEntriesIt->getValue();
// We also use presumed locations here to improve reproducibility for
// preprocessed inputs.
if (PresumedLoc PLoc = SM.getPresumedLoc(DiagLoc); PLoc.isValid())
return globsMatches(
CategoriesToMatchers,
llvm::sys::path::remove_leading_dotslash(PLoc.getFilename()));
return false;
}

bool WarningsSpecialCaseList::globsMatches(
const llvm::StringMap<Matcher> &CategoriesToMatchers,
StringRef FilePath) const {
StringRef LongestMatch;
bool LongestIsPositive = false;
for (const auto &Entry : CategoriesToMatchers) {
StringRef Category = Entry.getKey();
const llvm::SpecialCaseList::Matcher &Matcher = Entry.getValue();
bool IsPositive = Category != "emit";
for (const auto &Glob : Matcher.Globs) {
if (Glob->Name.size() < LongestMatch.size())
continue;
if (!Glob->Pattern.match(FilePath))
continue;
LongestMatch = Glob->Name;
LongestIsPositive = IsPositive;
}
}
return LongestIsPositive;
StringRef LongestEmit = DiagSection->getLongestMatch("src", F, "emit");
if (LongestEmit.empty())
return true;

return LongestSup.size() > LongestEmit.size();
}

bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId,
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Basic/ProfileList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class ProfileSpecialCaseList : public llvm::SpecialCaseList {
createOrDie(const std::vector<std::string> &Paths,
llvm::vfs::FileSystem &VFS);

bool isEmpty() const { return Sections.empty(); }
bool isEmpty() const { return sections().empty(); }

bool hasPrefix(StringRef Prefix) const {
for (const auto &It : Sections)
for (const auto &It : sections())
if (It.Entries.count(Prefix) > 0)
return true;
return false;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/SanitizerSpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
}

void SanitizerSpecialCaseList::createSanitizerSections() {
for (const auto &S : Sections) {
for (const auto &S : sections()) {
SanitizerMask Mask;

#define SANITIZER(NAME, ID) \
Expand Down
75 changes: 52 additions & 23 deletions llvm/include/llvm/Support/SpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
#ifndef LLVM_SUPPORT_SPECIALCASELIST_H
#define LLVM_SUPPORT_SPECIALCASELIST_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/Regex.h"
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>

namespace llvm {
Expand Down Expand Up @@ -118,20 +120,34 @@ class SpecialCaseList {
SpecialCaseList(SpecialCaseList const &) = delete;
SpecialCaseList &operator=(SpecialCaseList const &) = delete;

/// Represents a set of globs and their line numbers
class Matcher {
private:
// Lagacy v1 matcher.
class RegexMatcher {
public:
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber,
bool UseRegex);
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
LLVM_ABI void
match(StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const;

LLVM_ABI bool matchAny(StringRef Query) const {
bool R = false;
match(Query, [&](StringRef, unsigned) { R = true; });
return R;
}
struct Reg {
Reg(StringRef Name, unsigned LineNo, Regex &&Rg)
: Name(Name), LineNo(LineNo), Rg(std::move(Rg)) {}
std::string Name;
unsigned LineNo;
Regex Rg;
Reg(Reg &&) = delete;
Reg() = default;
};

std::vector<std::unique_ptr<Reg>> RegExes;
};

class GlobMatcher {
public:
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
LLVM_ABI void
match(StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const;

struct Glob {
Glob(StringRef Name, unsigned LineNo) : Name(Name), LineNo(LineNo) {}
Expand All @@ -144,25 +160,35 @@ class SpecialCaseList {
Glob() = default;
};

struct Reg {
Reg(StringRef Name, unsigned LineNo, Regex &&Rg)
: Name(Name), LineNo(LineNo), Rg(std::move(Rg)) {}
std::string Name;
unsigned LineNo;
Regex Rg;
Reg(Reg &&) = delete;
Reg() = default;
};
std::vector<std::unique_ptr<Glob>> Globs;
};

std::vector<std::unique_ptr<Matcher::Glob>> Globs;
std::vector<std::unique_ptr<Reg>> RegExes;
/// Represents a set of patterns and their line numbers
class Matcher {
public:
LLVM_ABI explicit Matcher(bool UseGlobs);

LLVM_ABI void
match(StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const;

LLVM_ABI bool matchAny(StringRef Query) const {
bool R = false;
match(Query, [&](StringRef, unsigned) { R = true; });
return R;
}

LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);

std::variant<RegexMatcher, GlobMatcher> M;
};

using SectionEntries = StringMap<StringMap<Matcher>>;

protected:
struct Section {
Section(StringRef Str, unsigned FileIdx)
: SectionStr(Str), FileIdx(FileIdx) {};
Section(StringRef Str, unsigned FileIdx, bool UseGlobs)
: SectionMatcher(UseGlobs), SectionStr(Str), FileIdx(FileIdx) {}

Section(Section &&) = default;

Expand All @@ -186,11 +212,14 @@ class SpecialCaseList {
findMatcher(StringRef Prefix, StringRef Category) const;
};

ArrayRef<const Section> sections() const { return Sections; }

private:
std::vector<Section> Sections;

LLVM_ABI Expected<Section *> addSection(StringRef SectionStr,
unsigned FileIdx, unsigned LineNo,
bool UseGlobs = true);
bool UseGlobs);

/// Parses just-constructed SpecialCaseList entries from a memory buffer.
LLVM_ABI bool parse(unsigned FileIdx, const MemoryBuffer *MB,
Expand Down
110 changes: 74 additions & 36 deletions llvm/lib/Support/SpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,55 +29,79 @@

namespace llvm {

Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber,
bool UseGlobs) {
Error SpecialCaseList::RegexMatcher::insert(StringRef Pattern,
unsigned LineNumber) {
if (Pattern.empty())
return createStringError(errc::invalid_argument,
Twine("Supplied ") +
(UseGlobs ? "glob" : "regex") + " was blank");

if (!UseGlobs) {
// Replace * with .*
auto Regexp = Pattern.str();
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
pos += strlen(".*")) {
Regexp.replace(pos, strlen("*"), ".*");
}
"Supplied regex was blank");

Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
// Replace * with .*
auto Regexp = Pattern.str();
for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std::string::npos;
pos += strlen(".*")) {
Regexp.replace(pos, strlen("*"), ".*");
}

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

auto Rg =
std::make_unique<Matcher::Reg>(Pattern, LineNumber, std::move(CheckRE));
RegExes.emplace_back(std::move(Rg));
// Check that the regexp is valid.
Regex CheckRE(Regexp);
std::string REError;
if (!CheckRE.isValid(REError))
return createStringError(errc::invalid_argument, REError);

return Error::success();
}
auto Rg = std::make_unique<Reg>(Pattern, LineNumber, std::move(CheckRE));
RegExes.emplace_back(std::move(Rg));

auto Glob = std::make_unique<Matcher::Glob>(Pattern, LineNumber);
return Error::success();
}

void SpecialCaseList::RegexMatcher::match(
StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const {
for (const auto &Regex : reverse(RegExes))
if (Regex->Rg.match(Query))
Cb(Regex->Name, Regex->LineNo);
}

Error SpecialCaseList::GlobMatcher::insert(StringRef Pattern,
unsigned LineNumber) {
if (Pattern.empty())
return createStringError(errc::invalid_argument, "Supplied glob was blank");

auto G = std::make_unique<Glob>(Pattern, 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)
.moveInto(Glob->Pattern))
if (auto Err = GlobPattern::create(G->Name, /*MaxSubPatterns=*/1024)
.moveInto(G->Pattern))
return Err;
Globs.push_back(std::move(Glob));
Globs.emplace_back(std::move(G));
return Error::success();
}

void SpecialCaseList::Matcher::match(
void SpecialCaseList::GlobMatcher::match(
StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const {
for (const auto &Glob : reverse(Globs))
if (Glob->Pattern.match(Query))
Cb(Glob->Name, Glob->LineNo);
for (const auto &Regex : reverse(RegExes))
if (Regex->Rg.match(Query))
Cb(Regex->Name, Regex->LineNo);
}

SpecialCaseList::Matcher::Matcher(bool UseGlobs) {
if (UseGlobs)
M.emplace<GlobMatcher>();
else
M.emplace<RegexMatcher>();
}

void SpecialCaseList::Matcher::match(
StringRef Query,
llvm::function_ref<void(StringRef Rule, unsigned LineNo)> Cb) const {
return std::visit([&](auto &V) { return V.match(Query, Cb); }, M);
}

Error SpecialCaseList::Matcher::insert(StringRef Pattern, unsigned LineNumber) {
return std::visit([&](auto &V) { return V.insert(Pattern, LineNumber); }, M);
}

// TODO: Refactor this to return Expected<...>
Expand Down Expand Up @@ -136,10 +160,10 @@ bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
Expected<SpecialCaseList::Section *>
SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
unsigned LineNo, bool UseGlobs) {
Sections.emplace_back(SectionStr, FileNo);
Sections.emplace_back(SectionStr, FileNo, UseGlobs);
auto &Section = Sections.back();

if (auto Err = Section.SectionMatcher.insert(SectionStr, LineNo, UseGlobs)) {
if (auto Err = Section.SectionMatcher.insert(SectionStr, LineNo)) {
return createStringError(errc::invalid_argument,
"malformed section at line " + Twine(LineNo) +
": '" + SectionStr +
Expand All @@ -165,7 +189,7 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
bool UseGlobs = Version > 1;

Section *CurrentSection;
if (auto Err = addSection("*", FileIdx, 1).moveInto(CurrentSection)) {
if (auto Err = addSection("*", FileIdx, 1, true).moveInto(CurrentSection)) {
Error = toString(std::move(Err));
return false;
}
Expand Down Expand Up @@ -204,8 +228,9 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
}

auto [Pattern, Category] = Postfix.split("=");
auto &Entry = CurrentSection->Entries[Prefix][Category];
if (auto Err = Entry.insert(Pattern, LineNo, UseGlobs)) {
auto [It, _] =
CurrentSection->Entries[Prefix].try_emplace(Category, UseGlobs);
if (auto Err = It->second.insert(Pattern, LineNo)) {
Error =
(Twine("malformed ") + (UseGlobs ? "glob" : "regex") + " in line " +
Twine(LineNo) + ": '" + Pattern + "': " + toString(std::move(Err)))
Expand Down Expand Up @@ -262,4 +287,17 @@ unsigned SpecialCaseList::Section::getLastMatch(StringRef Prefix,
return LastLine;
}

StringRef SpecialCaseList::Section::getLongestMatch(StringRef Prefix,
StringRef Query,
StringRef Category) const {
StringRef LongestRule;
if (const Matcher *M = findMatcher(Prefix, Category)) {
M->match(Query, [&](StringRef Rule, unsigned) {
if (LongestRule.size() < Rule.size())
LongestRule = Rule;
});
}
return LongestRule;
}

} // namespace llvm
Loading