Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
72 changes: 48 additions & 24 deletions llvm/include/llvm/Support/SpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>

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

private:
/// Represents a set of globs and their line numbers
class Matcher {
// 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 @@ -146,27 +160,37 @@ 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;
bool RemoveDotSlash = false;
/// Represents a set of patterns and their line numbers
class Matcher {
public:
LLVM_ABI Matcher(bool UseGlobs, bool RemoveDotSlash);

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;
bool RemoveDotSlash;
};

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, /*RemoveDotSlash=*/false), SectionStr(Str),
FileIdx(FileIdx) {}

Section(Section &&) = default;

Expand Down Expand Up @@ -197,7 +221,7 @@ class SpecialCaseList {

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
105 changes: 65 additions & 40 deletions llvm/lib/Support/SpecialCaseList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,57 +30,82 @@

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");

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

Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();
Regexp = (Twine("^(") + StringRef(Regexp) + ")$").str();

// Check that the regexp is valid.
Regex CheckRE(Regexp);
std::string REError;
if (!CheckRE.isValid(REError))
return createStringError(errc::invalid_argument, REError);
// Check that the regexp is valid.
Regex CheckRE(Regexp);
std::string REError;
if (!CheckRE.isValid(REError))
return createStringError(errc::invalid_argument, REError);

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

return Error::success();
}
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 Glob = std::make_unique<Matcher::Glob>(Pattern, LineNumber);
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 {
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);
for (const auto &Regex : reverse(RegExes))
if (Regex->Rg.match(Query))
Cb(Regex->Name, Regex->LineNo);
}

SpecialCaseList::Matcher::Matcher(bool UseGlobs, bool RemoveDotSlash)
: RemoveDotSlash(RemoveDotSlash) {
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 {
if (RemoveDotSlash)
Query = llvm::sys::path::remove_leading_dotslash(Query);
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 @@ -139,10 +164,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 Down Expand Up @@ -170,7 +195,7 @@ bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
bool RemoveDotSlash = Version > 2;

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 @@ -213,10 +238,10 @@ 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)) {
auto [It, _] = CurrentSection->Entries[Prefix].try_emplace(
Category, UseGlobs,
RemoveDotSlash && llvm::is_contained(PathPrefixes, Prefix));
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
Loading