28#include <system_error>
34 unsigned LineNumber) {
37 "Supplied regex was blank");
40 auto Regexp = Pattern.str();
41 for (
size_t pos = 0; (pos = Regexp.find(
'*', pos)) != std::string::npos;
42 pos += strlen(
".*")) {
43 Regexp.replace(pos, strlen(
"*"),
".*");
46 Regexp = (Twine(
"^(") + StringRef(Regexp) +
")$").str();
49 Regex CheckRE(Regexp);
51 if (!CheckRE.isValid(REError))
54 RegExes.emplace_back(Pattern, LineNumber, std::move(CheckRE));
58void SpecialCaseList::RegexMatcher::preprocess(
bool BySize) {
61 return A.Name.size() <
B.Name.size();
66void SpecialCaseList::RegexMatcher::match(
68 llvm::function_ref<
void(StringRef Rule,
unsigned LineNo)> Cb)
const {
69 for (
const auto &R :
reverse(RegExes))
70 if (
R.Rg.match(Query))
71 return Cb(
R.Name,
R.LineNo);
74Error SpecialCaseList::GlobMatcher::insert(StringRef Pattern,
75 unsigned LineNumber) {
80 if (
auto Err = Res.takeError())
82 Globs.emplace_back(Pattern, LineNumber, std::move(Res.get()));
86void SpecialCaseList::GlobMatcher::preprocess(
bool BySize) {
89 return A.Name.size() <
B.Name.size();
94void SpecialCaseList::GlobMatcher::match(
96 llvm::function_ref<
void(StringRef Rule,
unsigned LineNo)> Cb)
const {
98 if (
G.Pattern.match(Query))
99 return Cb(
G.Name,
G.LineNo);
102SpecialCaseList::Matcher::Matcher(
bool UseGlobs,
bool RemoveDotSlash)
103 : RemoveDotSlash(RemoveDotSlash) {
105 M.emplace<GlobMatcher>();
107 M.emplace<RegexMatcher>();
110Error SpecialCaseList::Matcher::insert(StringRef Pattern,
unsigned LineNumber) {
111 return std::visit([&](
auto &V) {
return V.insert(Pattern, LineNumber); }, M);
114LLVM_ABI void SpecialCaseList::Matcher::preprocess(
bool BySize) {
115 return std::visit([&](
auto &V) {
return V.preprocess(BySize); }, M);
118void SpecialCaseList::Matcher::match(
123 return std::visit([&](
auto &V) {
return V.match(Query, Cb); }, M);
127std::unique_ptr<SpecialCaseList>
131 if (SCL->createInternal(Paths, FS,
Error))
137 std::string &
Error) {
139 if (SCL->createInternal(MB,
Error))
144std::unique_ptr<SpecialCaseList>
155 for (
size_t i = 0; i < Paths.size(); ++i) {
156 const auto &Path = Paths[i];
159 if (std::error_code EC = FileOrErr.
getError()) {
160 Error = (
Twine(
"can't open file '") + Path +
"': " + EC.message()).str();
163 std::string ParseError;
164 if (!
parse(i, FileOrErr.
get().get(), ParseError,
false)) {
165 Error = (
Twine(
"error parsing file '") + Path +
"': " + ParseError).str();
180SpecialCaseList::addSection(
StringRef SectionStr,
unsigned FileNo,
181 unsigned LineNo,
bool UseGlobs) {
182 Sections.emplace_back(SectionStr, FileNo, UseGlobs);
183 auto &Section = Sections.back();
185 SectionStr = SectionStr.
copy(StrAlloc);
186 if (
auto Err = Section.SectionMatcher.insert(SectionStr, LineNo)) {
188 "malformed section at line " +
Twine(LineNo) +
196bool SpecialCaseList::parse(
unsigned FileIdx,
const MemoryBuffer *MB,
197 std::string &Error,
bool OrderBySize) {
198 unsigned long long Version = 2;
200 StringRef Header = MB->getBuffer();
201 if (Header.consume_front(
"#!special-case-list-v"))
209 bool UseGlobs = Version > 1;
211 bool RemoveDotSlash = Version > 2;
214 if (
auto Err =
addSection(
"*", FileIdx, 1,
true).moveInto(CurrentSection)) {
221 constexpr StringRef PathPrefixes[] = {
"src",
"!src",
"mainfile",
"source"};
223 for (line_iterator LineIt(*MB,
true,
'#');
224 !LineIt.is_at_eof(); LineIt++) {
225 unsigned LineNo = LineIt.line_number();
226 StringRef Line = LineIt->trim();
231 if (Line.starts_with(
"[")) {
232 if (!Line.ends_with(
"]")) {
234 (
"malformed section header on line " + Twine(LineNo) +
": " + Line)
239 if (
auto Err =
addSection(Line.drop_front().drop_back(), FileIdx, LineNo,
241 .moveInto(CurrentSection)) {
249 auto [
Prefix, Postfix] = Line.split(
":");
250 if (Postfix.empty()) {
252 Error = (
"malformed line " + Twine(LineNo) +
": '" + Line +
"'").str();
256 auto [Pattern, Category] = Postfix.split(
"=");
257 auto [It,
_] = CurrentSection->Entries[
Prefix].try_emplace(
260 Pattern = Pattern.copy(StrAlloc);
261 if (
auto Err = It->second.insert(Pattern, LineNo)) {
263 (Twine(
"malformed ") + (UseGlobs ?
"glob" :
"regex") +
" in line " +
264 Twine(LineNo) +
": '" + Pattern +
"': " +
toString(std::move(Err)))
270 for (Section &S : Sections)
271 S.preprocess(OrderBySize);
276SpecialCaseList::~SpecialCaseList() =
default;
284std::pair<unsigned, unsigned>
287 for (
const auto &S :
reverse(Sections)) {
288 if (S.SectionMatcher.matchAny(
Section)) {
289 unsigned Blame = S.getLastMatch(Prefix, Query, Category);
291 return {S.FileIdx, Blame};
297const SpecialCaseList::Matcher *
298SpecialCaseList::Section::findMatcher(
StringRef Prefix,
300 SectionEntries::const_iterator
I = Entries.find(Prefix);
301 if (
I == Entries.end())
304 if (
II ==
I->second.end())
310LLVM_ABI void SpecialCaseList::Section::preprocess(
bool OrderBySize) {
311 SectionMatcher.preprocess(
false);
312 for (
auto &[K1,
E] : Entries)
313 for (
auto &[K2, M] :
E)
314 M.preprocess(OrderBySize);
320 unsigned LastLine = 0;
321 if (
const Matcher *M = findMatcher(Prefix, Category)) {
322 M->match(Query, [&](
StringRef,
unsigned LineNo) {
323 LastLine = std::max(LastLine, LineNo);
333 if (
const Matcher *M = findMatcher(Prefix, Category)) {
334 M->match(Query, [&](
StringRef Rule,
unsigned) {
335 if (LongestRule.
size() < Rule.
size())
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static llvm::Error parse(DataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
static const char * toString(MIToken::TokenKind TokenKind)
static Error addSection(const NewSectionInfo &NewSection, Object &Obj)
uint64_t IntrinsicInst * II
Defines the virtual file system interface vfs::FileSystem.
Represents either an error or a value T.
std::error_code getError() const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={})
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static constexpr std::pair< unsigned, unsigned > NotFound
LLVM_ABI std::pair< unsigned, unsigned > inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category=StringRef()) const
Returns the file index and the line number <FileIdx, LineNo> corresponding to the special case list e...
LLVM_ABI bool createInternal(const std::vector< std::string > &Paths, vfs::FileSystem &VFS, std::string &Error)
static LLVM_ABI std::unique_ptr< SpecialCaseList > createOrDie(const std::vector< std::string > &Paths, llvm::vfs::FileSystem &FS)
Parses the special case list entries from files.
static LLVM_ABI std::unique_ptr< SpecialCaseList > create(const std::vector< std::string > &Paths, llvm::vfs::FileSystem &FS, std::string &Error)
Parses the special case list entries from files.
SpecialCaseList()=default
LLVM_ABI bool inSection(StringRef Section, StringRef Prefix, StringRef Query, StringRef Category=StringRef()) const
Returns true, if special case list contains a line.
StringMapIterBase< ValueTy, true > const_iterator
StringRef - Represent a constant reference to a string, i.e.
constexpr size_t size() const
size - Get the string size.
StringRef copy(Allocator &A) const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
An efficient, type-erasing, non-owning reference to a callable.
The virtual file system interface.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)
This is a convenience method that opens a file, gets its content and then closes the file.
LLVM_ABI StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI bool consumeUnsignedInteger(StringRef &Str, unsigned Radix, unsigned long long &Result)
auto reverse(ContainerTy &&C)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI StringRef getLongestMatch(StringRef Prefix, StringRef Query, StringRef Category) const
LLVM_ABI unsigned getLastMatch(StringRef Prefix, StringRef Query, StringRef Category) const