LLVM: lib/Support/SpecialCaseList.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

30#include

31#include <stdio.h>

32#include

33#include <system_error>

34#include

35#include

36#include

37

38namespace llvm {

39

40namespace {

41

42

43class RegexMatcher {

44public:

45 Error insert(StringRef Pattern, unsigned LineNumber);

46 unsigned match(StringRef Query) const;

47

48private:

49 struct Reg {

50 Reg(StringRef Name, unsigned LineNo, Regex &&Rg)

51 : Name(Name), LineNo(LineNo), Rg(std::move(Rg)) {}

52 StringRef Name;

53 unsigned LineNo;

55 };

56

57 std::vector RegExes;

58};

59

60class GlobMatcher {

61public:

62 Error insert(StringRef Pattern, unsigned LineNumber);

63 unsigned match(StringRef Query) const;

64

65private:

66 struct Glob {

67 Glob(StringRef Name, unsigned LineNo, GlobPattern &&Pattern)

68 : Name(Name), LineNo(LineNo), Pattern(std::move(Pattern)) {}

69 StringRef Name;

70 unsigned LineNo;

71 GlobPattern Pattern;

72 };

73

74 void LazyInit() const;

75

76 std::vectorGlobMatcher::Glob Globs;

77

78 mutable RadixTree<iterator_rangeStringRef::const\_iterator,

79 RadixTree<iterator_rangeStringRef::const\_reverse\_iterator,

81 PrefixSuffixToGlob;

82

83 mutable RadixTree<iterator_rangeStringRef::const\_iterator,

85 SubstrToGlob;

86

87 mutable bool Initialized = false;

88};

89

90

91class Matcher {

92public:

93 Matcher(bool UseGlobs, bool RemoveDotSlash);

94

95 Error insert(StringRef Pattern, unsigned LineNumber);

96 unsigned match(StringRef Query) const;

97

98 bool matchAny(StringRef Query) const { return match(Query); }

99

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

101 bool RemoveDotSlash;

102};

103

105 if (Pattern.empty())

107 "Supplied regex was blank");

108

109

110 auto Regexp = Pattern.str();

111 for (size_t pos = 0; (pos = Regexp.find('*', pos)) != std:🧵:npos;

112 pos += strlen(".*")) {

113 Regexp.replace(pos, strlen("*"), ".*");

114 }

115

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

117

118

119 Regex CheckRE(Regexp);

120 std::string REError;

121 if (!CheckRE.isValid(REError))

123

124 RegExes.emplace_back(Pattern, LineNumber, std::move(CheckRE));

125 return Error::success();

126}

127

128unsigned RegexMatcher::match(StringRef Query) const {

129 for (const auto &R : reverse(RegExes))

130 if (R.Rg.match(Query))

131 return R.LineNo;

132 return 0;

133}

134

135Error GlobMatcher::insert(StringRef Pattern, unsigned LineNumber) {

136 if (Pattern.empty())

137 return createStringError(errc::invalid_argument, "Supplied glob was blank");

138

139 auto Res = GlobPattern::create(Pattern, 1024);

140 if (auto Err = Res.takeError())

141 return Err;

142 Globs.emplace_back(Pattern, LineNumber, std::move(Res.get()));

143 return Error::success();

144}

145

146void GlobMatcher::LazyInit() const {

148 return;

149 Initialized = true;

150 for (const auto &[Idx, G] : enumerate(Globs)) {

151 StringRef Prefix = G.Pattern.prefix();

152 StringRef Suffix = G.Pattern.suffix();

153

154 if (Suffix.empty() && Prefix.empty()) {

155

156

157 StringRef Substr = G.Pattern.longest_substr();

158 if (!Substr.empty()) {

159

160

161 auto &V = SubstrToGlob.emplace(Substr).first->second;

162 V.emplace_back(Idx);

163 continue;

164 }

165 }

166

167 auto &SToGlob = PrefixSuffixToGlob.emplace(Prefix).first->second;

168 auto &V = SToGlob.emplace(reverse(Suffix)).first->second;

169 V.emplace_back(Idx);

170 }

171}

172

173unsigned GlobMatcher::match(StringRef Query) const {

174 LazyInit();

175

176 int Best = -1;

177 if (!PrefixSuffixToGlob.empty()) {

178 for (const auto &[_, SToGlob] : PrefixSuffixToGlob.find_prefixes(Query)) {

179 for (const auto &[_, V] : SToGlob.find_prefixes(reverse(Query))) {

180 for (int Idx : reverse(V)) {

181 if (Best > Idx)

182 break;

183 const GlobMatcher::Glob &G = Globs[Idx];

184 if (G.Pattern.match(Query)) {

185 Best = Idx;

186

187

188

189

190 break;

191 }

192 }

193 }

194 }

195 }

196

197 if (!SubstrToGlob.empty()) {

198

199

200 for (StringRef Q = Query; !Q.empty(); Q = Q.drop_front()) {

201 for (const auto &[_, V] : SubstrToGlob.find_prefixes(Q)) {

202 for (int Idx : reverse(V)) {

203 if (Best > Idx)

204 break;

205 const GlobMatcher::Glob &G = Globs[Idx];

206 if (G.Pattern.match(Query)) {

207 Best = Idx;

208

209

210

211

212 break;

213 }

214 }

215 }

216 }

217 }

218 return Best < 0 ? 0 : Globs[Best].LineNo;

219}

220

221Matcher::Matcher(bool UseGlobs, bool RemoveDotSlash)

222 : RemoveDotSlash(RemoveDotSlash) {

223 if (UseGlobs)

224 M.emplace();

225 else

226 M.emplace();

227}

228

229Error Matcher::insert(StringRef Pattern, unsigned LineNumber) {

230 return std::visit([&](auto &V) { return V.insert(Pattern, LineNumber); }, M);

231}

232

233unsigned Matcher::match(StringRef Query) const {

234 if (RemoveDotSlash)

236 return std::visit([&](auto &V) -> unsigned { return V.match(Query); }, M);

237}

238}

239

241public:

243

245

248

251};

252

253

254std::unique_ptr

257 std::unique_ptr SCL(new SpecialCaseList());

258 if (SCL->createInternal(Paths, FS, Error))

259 return SCL;

260 return nullptr;

261}

262

264 std::string &Error) {

265 std::unique_ptr SCL(new SpecialCaseList());

266 if (SCL->createInternal(MB, Error))

267 return SCL;

268 return nullptr;

269}

270

271std::unique_ptr

274 std::string Error;

276 return SCL;

278}

279

282 for (size_t i = 0; i < Paths.size(); ++i) {

283 const auto &Path = Paths[i];

286 if (std::error_code EC = FileOrErr.getError()) {

287 Error = (Twine("can't open file '") + Path + "': " + EC.message()).str();

288 return false;

289 }

290 std::string ParseError;

291 if (parse(i, FileOrErr.get().get(), ParseError)) {

292 Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();

293 return false;

294 }

295 }

296 return true;

297}

298

300 std::string &Error) {

302 return false;

303 return true;

304}

305

307SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,

308 unsigned LineNo, bool UseGlobs) {

309 SectionStr = SectionStr.copy(StrAlloc);

310 Sections.emplace_back(SectionStr, FileNo, UseGlobs);

311 auto &Section = Sections.back();

312

313 if (auto Err = Section.Impl->SectionMatcher.insert(SectionStr, LineNo)) {

315 "malformed section at line " + Twine(LineNo) +

316 ": '" + SectionStr +

317 "': " + toString(std::move(Err)));

318 }

319

320 return &Section;

321}

322

323bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,

324 std::string &Error) {

325 unsigned long long Version = 2;

326

327 StringRef Header = MB->getBuffer();

328 if (Header.consume_front("#!special-case-list-v"))

330

331

332

333

334

335

336 bool UseGlobs = Version > 1;

337

338 bool RemoveDotSlash = Version > 2;

339

340 auto ErrOrSection = addSection("*", FileIdx, 1, true);

341 if (auto Err = ErrOrSection.takeError()) {

342 Error = toString(std::move(Err));

343 return false;

344 }

345 Section::SectionImpl *CurrentImpl = ErrOrSection.get()->Impl.get();

346

347

348

349 constexpr StringRef PathPrefixes[] = {"src", "!src", "mainfile", "source"};

350

351 for (line_iterator LineIt(*MB, true, '#');

352 !LineIt.is_at_eof(); LineIt++) {

353 unsigned LineNo = LineIt.line_number();

354 StringRef Line = LineIt->trim();

355 if (Line.empty())

356 continue;

357

358

359 if (Line.starts_with("[")) {

360 if (!Line.ends_with("]")) {

361 Error =

362 ("malformed section header on line " + Twine(LineNo) + ": " + Line)

363 .str();

364 return false;

365 }

366

367 auto ErrOrSection =

368 addSection(Line.drop_front().drop_back(), FileIdx, LineNo, UseGlobs);

369 if (auto Err = ErrOrSection.takeError()) {

370 Error = toString(std::move(Err));

371 return false;

372 }

373 CurrentImpl = ErrOrSection.get()->Impl.get();

374 continue;

375 }

376

377

378 auto [Prefix, Postfix] = Line.split(":");

379 if (Postfix.empty()) {

380

381 Error = ("malformed line " + Twine(LineNo) + ": '" + Line + "'").str();

382 return false;

383 }

384

385 auto [Pattern, Category] = Postfix.split("=");

386 auto [It, _] = CurrentImpl->Entries[Prefix].try_emplace(

387 Category, UseGlobs,

389 Pattern = Pattern.copy(StrAlloc);

390 if (auto Err = It->second.insert(Pattern, LineNo)) {

391 Error =

392 (Twine("malformed ") + (UseGlobs ? "glob" : "regex") + " in line " +

393 Twine(LineNo) + ": '" + Pattern + "': " + toString(std::move(Err)))

394 .str();

395 return false;

396 }

397 }

398

399 return true;

400}

401

402SpecialCaseList::~SpecialCaseList() = default;

403

409

410std::pair<unsigned, unsigned>

413 for (const auto &S : reverse(Sections)) {

414 if (S.Impl->SectionMatcher.matchAny(Section)) {

415 unsigned Blame = S.getLastMatch(Prefix, Query, Category);

416 if (Blame)

417 return {S.FileIdx, Blame};

418 }

419 }

421}

422

424 bool UseGlobs)

425 : Name(Str), FileIdx(FileIdx),

427

429

431

433 return Impl->SectionMatcher.matchAny(Name);

434}

435

436const Matcher *

441 return nullptr;

443 if (II == I->second.end())

444 return nullptr;

445

446 return &II->second;

447}

448

452 if (const Matcher *M = Impl->findMatcher(Prefix, Category))

453 return M->match(Query);

454 return 0;

455}

456

458 return Impl->Entries.contains(Prefix);

459}

460

461}

This file defines the StringMap class.

#define LLVM_LIKELY(EXPR)

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

This file defines the SmallVector class.

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.

Tagged union holding either a T or a Error.

This interface provides simple read-only access to a block of memory, and provides simple methods for...

StringMap< StringMap< Matcher > > SectionEntries

Definition SpecialCaseList.cpp:244

const Matcher * findMatcher(StringRef Prefix, StringRef Category) const

Definition SpecialCaseList.cpp:437

SectionImpl(bool UseGlobs)

Definition SpecialCaseList.cpp:246

Matcher SectionMatcher

Definition SpecialCaseList.cpp:249

SectionEntries Entries

Definition SpecialCaseList.cpp:250

LLVM_ABI Section(StringRef Name, unsigned FileIdx, bool UseGlobs)

Definition SpecialCaseList.cpp:423

LLVM_ABI bool hasPrefix(StringRef Prefix) const

Returns true if the section has any entries for the given prefix.

Definition SpecialCaseList.cpp:457

LLVM_ABI unsigned getLastMatch(StringRef Prefix, StringRef Query, StringRef Category) const

Definition SpecialCaseList.cpp:449

LLVM_ABI bool matchName(StringRef Name) const

Definition SpecialCaseList.cpp:432

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...

Definition SpecialCaseList.cpp:411

LLVM_ABI bool createInternal(const std::vector< std::string > &Paths, vfs::FileSystem &VFS, std::string &Error)

Definition SpecialCaseList.cpp:280

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.

Definition SpecialCaseList.cpp:272

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.

Definition SpecialCaseList.cpp:255

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.

Definition SpecialCaseList.cpp:404

StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...

StringMapIterBase< StringMap< Matcher >, true > const_iterator

StringRef - Represent a constant reference to a string, i.e.

StringRef copy(Allocator &A) const

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

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.

This provides a very simple, boring adaptor for a begin and end iterator into a range type.

bool match(Val *V, const Pattern &P)

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.

auto enumerate(FirstRange &&First, RestRanges &&...Rest)

Given two or more input ranges, returns a new range whose values are tuples (A, B,...

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)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

Implement std::hash so that hash_code can be used in STL containers.