clang: lib/Frontend/VerifyDiagnosticConsumer.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

29#include "llvm/ADT/STLExtras.h"

30#include "llvm/ADT/SmallPtrSet.h"

31#include "llvm/ADT/SmallString.h"

32#include "llvm/ADT/StringRef.h"

33#include "llvm/ADT/Twine.h"

34#include "llvm/Support/ErrorHandling.h"

35#include "llvm/Support/Regex.h"

36#include "llvm/Support/raw_ostream.h"

37#include

38#include

39#include

40#include

41#include

42#include

43#include

44#include

45#include

46

47using namespace clang;

48

52

53#ifndef NDEBUG

54

55namespace {

56

57class VerifyFileTracker : public PPCallbacks {

60

61public:

63 : Verify(Verify), SM(SM) {}

64

65

66

69 FileID PrevFID) override {

72 }

73};

74

75}

76

77#endif

78

79

80

81

82

85

86namespace {

87

88

89class StandardDirective : public Directive {

90public:

92 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,

93 unsigned Min, unsigned Max)

94 : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,

96

97 bool isValid(std::string &Error) override {

98

99 return true;

100 }

101

102 bool match(StringRef S) override { return S.contains(Text); }

103};

104

105

106class RegexDirective : public Directive {

107public:

109 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,

110 unsigned Min, unsigned Max, StringRef RegexStr)

111 : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,

113 Regex(RegexStr) {}

114

115 bool isValid(std::string &Error) override {

116 return Regex.isValid(Error);

117 }

118

119 bool match(StringRef S) override {

120 return Regex.match(S);

121 }

122

123private:

124 llvm::Regex Regex;

125};

126

127class ParseHelper

128{

129public:

130 ParseHelper(StringRef S)

132

133

134 bool Next(StringRef S) {

135 P = C;

136 PEnd = C + S.size();

137 if (PEnd > End)

138 return false;

139 return memcmp(P, S.data(), S.size()) == 0;

140 }

141

142

143

144 bool Next(unsigned &N) {

145 unsigned TMP = 0;

146 P = C;

147 PEnd = P;

148 for (; PEnd < End && *PEnd >= '0' && *PEnd <= '9'; ++PEnd) {

149 TMP *= 10;

150 TMP += *PEnd - '0';

151 }

152 if (PEnd == C)

153 return false;

154 N = TMP;

155 return true;

156 }

157

158

159

160 bool NextMarker() {

161 P = C;

162 if (P == End || *P != '#')

163 return false;

164 PEnd = P;

165 ++PEnd;

166 while ((isAlphanumeric(*PEnd) || *PEnd == '-' || *PEnd == '_') &&

167 PEnd < End)

168 ++PEnd;

169 return PEnd > P + 1;

170 }

171

172

173

174

175

176

177

178

179

180

181 bool Search(StringRef S, bool EnsureStartOfWord = false,

182 bool FinishDirectiveToken = false) {

183 do {

184 if (!S.empty()) {

185 P = std::search(C, End, S.begin(), S.end());

186 PEnd = P + S.size();

187 }

188 else {

189 P = C;

191 ++P;

192 PEnd = P + 1;

193 }

194 if (P == End)

195 break;

196

197 if (EnsureStartOfWord

198

200

201 || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')

202 && P[-2] == '/')))

203 continue;

204 if (FinishDirectiveToken) {

206 || *PEnd == '-' || *PEnd == '_'))

207 ++PEnd;

208

209

210

211

212

213 assert(isLetter(*P) && "-verify prefix must start with a letter");

214 while (isDigit(PEnd[-1]) || PEnd[-1] == '-')

215 --PEnd;

216 }

217 return true;

218 } while (Advance());

219 return false;

220 }

221

222

223

224 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {

225 unsigned Depth = 1;

226 P = C;

227 while (P < End) {

228 StringRef S(P, End - P);

229 if (S.starts_with(OpenBrace)) {

230 ++Depth;

231 P += OpenBrace.size();

232 } else if (S.starts_with(CloseBrace)) {

233 --Depth;

234 if (Depth == 0) {

235 PEnd = P + CloseBrace.size();

236 return true;

237 }

238 P += CloseBrace.size();

239 } else {

240 ++P;

241 }

242 }

243 return false;

244 }

245

246

247

248 bool Advance() {

249 C = PEnd;

250 return C < End;

251 }

252

253

254

255 StringRef Match() { return StringRef(P, PEnd - P); }

256

257

258 void SkipWhitespace() {

260 ;

261 }

262

263

264 bool Done() {

265 return !(C < End);

266 }

267

268

269 const char * const Begin;

270

271

272 const char * const End;

273

274

275 const char *C;

276

277

278 const char *P;

279

280private:

281

282 const char *PEnd = nullptr;

283};

284

285

286struct UnattachedDirective {

288 bool RegexKind = false;

290 std::string Text;

291 unsigned Min = 1, Max = 1;

292};

293

294

295

296void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,

298 bool MatchAnyFileAndLine = false,

299 bool MatchAnyLine = false) {

300

302 UD.RegexKind, UD.DirectivePos, ExpectedLoc, MatchAnyFileAndLine,

303 MatchAnyLine, UD.Text, UD.Min, UD.Max);

304

305 std::string Error;

306 if (D->isValid(Error)) {

307 Diags.Report(UD.ContentBegin, diag::err_verify_invalid_content)

308 << (UD.RegexKind ? "regex" : "string") << Error;

309 }

310

311 UD.DL->push_back(std::move(D));

312}

313

314}

315

316

317

318

319

320

321

322

323

324

325

328

329 struct Marker {

333 };

334 llvm::StringMap Markers;

335

336

337

338 llvm::StringMap<llvm::SmallVector<UnattachedDirective, 2>> DeferredDirectives;

339

340public:

342

343

345 auto InsertResult = Markers.insert(

347

348 Marker &M = InsertResult.first->second;

349 if (!InsertResult.second) {

350

351 M.RedefLoc = Pos;

352 } else {

353

354 auto Deferred = DeferredDirectives.find(MarkerName);

355 if (Deferred != DeferredDirectives.end()) {

356 for (auto &UD : Deferred->second) {

357 if (M.UseLoc.isInvalid())

358 M.UseLoc = UD.DirectivePos;

359 attachDirective(Diags, UD, Pos);

360 }

361 DeferredDirectives.erase(Deferred);

362 }

363 }

364 }

365

366

367 void addDirective(StringRef MarkerName, const UnattachedDirective &UD) {

368 auto MarkerIt = Markers.find(MarkerName);

369 if (MarkerIt != Markers.end()) {

370 Marker &M = MarkerIt->second;

371 if (M.UseLoc.isInvalid())

372 M.UseLoc = UD.DirectivePos;

373 return attachDirective(Diags, UD, M.DefLoc);

374 }

375 DeferredDirectives[MarkerName].push_back(UD);

376 }

377

378

379

381 for (auto &MarkerInfo : Markers) {

382 StringRef Name = MarkerInfo.first();

383 Marker &M = MarkerInfo.second;

384 if (M.RedefLoc.isValid() && M.UseLoc.isValid()) {

385 Diags.Report(M.UseLoc, diag::err_verify_ambiguous_marker) << Name;

386 Diags.Report(M.DefLoc, diag::note_verify_ambiguous_marker) << Name;

387 Diags.Report(M.RedefLoc, diag::note_verify_ambiguous_marker) << Name;

388 }

389 }

390

391 for (auto &DeferredPair : DeferredDirectives) {

392 Diags.Report(DeferredPair.second.front().DirectivePos,

393 diag::err_verify_no_such_marker)

394 << DeferredPair.first();

395 }

396 }

397};

398

401 return "expected";

403}

404

405

406

407

408

414

415

416 for (ParseHelper PH(S); !PH.Done();) {

417 if (!PH.Search("#", true))

418 break;

419 PH.C = PH.P;

420 if (!PH.NextMarker()) {

421 PH.Next("#");

422 PH.Advance();

423 continue;

424 }

425 PH.Advance();

426 Markers.addMarker(PH.Match(), Pos);

427 }

428

429

430 bool FoundDirective = false;

431 for (ParseHelper PH(S); !PH.Done();) {

432

433

434

436 if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)

437 : PH.Search("", true, true)))

438 break;

439

440 StringRef DToken = PH.Match();

441 PH.Advance();

442

443

444 UnattachedDirective D;

445 const char *KindStr = "string";

446

447

448

449

450

451

452

453

454 if (DToken.consume_back("-re")) {

455 D.RegexKind = true;

456 KindStr = "regex";

457 }

458

459

462 if (DToken.ends_with(DType = "-error"))

463 D.DL = ED ? &ED->Errors : nullptr;

464 else if (DToken.ends_with(DType = "-warning"))

465 D.DL = ED ? &ED->Warnings : nullptr;

466 else if (DToken.ends_with(DType = "-remark"))

467 D.DL = ED ? &ED->Remarks : nullptr;

468 else if (DToken.ends_with(DType = "-note"))

469 D.DL = ED ? &ED->Notes : nullptr;

470 else if (DToken.ends_with(DType = "-no-diagnostics")) {

472 if (D.RegexKind)

473 continue;

474 } else

475 continue;

476 DToken = DToken.substr(0, DToken.size()-DType.size());

477

478

479

480

481 if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))

482 continue;

483

486 Diags.Report(Pos, diag::err_verify_invalid_no_diags)

488 else

490 continue;

491 }

493 Diags.Report(Pos, diag::err_verify_invalid_no_diags)

495 continue;

496 }

498

499

500

501 if (D.DL)

502 return true;

503

504

506 StringRef Marker;

507 bool MatchAnyFileAndLine = false;

508 bool MatchAnyLine = false;

509 if (!PH.Next("@")) {

510 ExpectedLoc = Pos;

511 } else {

512 PH.Advance();

513 unsigned Line = 0;

514 bool FoundPlus = PH.Next("+");

515 if (FoundPlus || PH.Next("-")) {

516

517 PH.Advance();

519 unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);

520 if (Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {

521 if (FoundPlus) ExpectedLine += Line;

522 else ExpectedLine -= Line;

523 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);

524 }

525 } else if (PH.Next(Line)) {

526

527 if (Line > 0)

528 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);

529 } else if (PH.NextMarker()) {

530 Marker = PH.Match();

531 } else if (PP && PH.Search(":")) {

532

533 StringRef Filename(PH.C, PH.P-PH.C);

534 PH.Advance();

535

537 MatchAnyFileAndLine = true;

538 if (!PH.Next("*")) {

540 diag::err_verify_missing_line)

541 << "'*'";

542 continue;

543 }

544 MatchAnyLine = true;

546 } else {

547

550 nullptr, nullptr, nullptr, nullptr, nullptr);

553 diag::err_verify_missing_file)

555 continue;

556 }

557

561

562 if (PH.Next(Line) && Line > 0)

563 ExpectedLoc = SM.translateLineCol(FID, Line, 1);

564 else if (PH.Next("*")) {

565 MatchAnyLine = true;

566 ExpectedLoc = SM.translateLineCol(FID, 1, 1);

567 }

568 }

569 } else if (PH.Next("*")) {

570 MatchAnyLine = true;

572 }

573

574 if (ExpectedLoc.isInvalid() && !MatchAnyLine && Marker.empty()) {

576 diag::err_verify_missing_line) << KindStr;

577 continue;

578 }

579 PH.Advance();

580 }

581

582

583 PH.SkipWhitespace();

584

585

586 if (PH.Next(D.Min)) {

587 PH.Advance();

588

589

590 if (PH.Next("+")) {

592 PH.Advance();

593 } else if (PH.Next("-")) {

594 PH.Advance();

595 if (!PH.Next(D.Max) || D.Max < D.Min) {

597 diag::err_verify_invalid_range) << KindStr;

598 continue;

599 }

600 PH.Advance();

601 } else {

602 D.Max = D.Min;

603 }

604 } else if (PH.Next("+")) {

605

607 PH.Advance();

608 }

609

610

611 PH.SkipWhitespace();

612

613

614 if (!PH.Next("{{")) {

616 diag::err_verify_missing_start) << KindStr;

617 continue;

618 }

620 const char *const DelimBegin = PH.C;

621 PH.Advance();

622

623 for (; D.RegexKind && PH.Next("{"); PH.Advance())

624 CloseBrace += '}';

625 const char* const ContentBegin = PH.C;

626

627 StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);

628 if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {

630 diag::err_verify_missing_end)

631 << KindStr << CloseBrace;

632 continue;

633 }

634 const char* const ContentEnd = PH.P;

635 PH.Advance();

636

637 D.DirectivePos = Pos;

639

640

641 StringRef NewlineStr = "\\n";

642 StringRef Content(ContentBegin, ContentEnd-ContentBegin);

643 size_t CPos = 0;

644 size_t FPos;

645 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {

646 D.Text += Content.substr(CPos, FPos-CPos);

647 D.Text += '\n';

648 CPos = FPos + NewlineStr.size();

649 }

650 if (D.Text.empty())

651 D.Text.assign(ContentBegin, ContentEnd);

652

653

654 if (D.RegexKind && D.Text.find("{{") == StringRef::npos) {

655 Diags.Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;

656 return false;

657 }

658

659 if (Marker.empty())

660 attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);

661 else

663 FoundDirective = true;

664 }

665

666 return FoundDirective;

667}

668

670 : Diags(Diags_), PrimaryClient(Diags.getClient()),

671 PrimaryClientOwner(Diags.takeClient()),

673 Status(HasNoDirectives) {

676}

677

679 assert(!ActiveSourceFiles && "Incomplete parsing of source files!");

680 assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");

681 SrcManager = nullptr;

682 CheckDiagnostics();

684 "The VerifyDiagnosticConsumer takes over ownership of the client!");

685}

686

687

688

691

692 if (++ActiveSourceFiles == 1) {

693 if (PP) {

694 CurrentPreprocessor = PP;

695 this->LangOpts = &LangOpts;

697 const_cast<Preprocessor *>(PP)->addCommentHandler(this);

698#ifndef NDEBUG

699

700 const_cast<Preprocessor *>(PP)->addPPCallbacks(

701 std::make_unique(*this, *SrcManager));

702#endif

703 }

704 }

705

706 assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");

708}

709

711 assert(ActiveSourceFiles && "No active source files!");

713

714

715 if (--ActiveSourceFiles == 0) {

716 if (CurrentPreprocessor)

717 const_cast<Preprocessor *>(CurrentPreprocessor)->

718 removeCommentHandler(this);

719

720

721 Markers->finalize();

722

723

724 CheckDiagnostics();

725 CurrentPreprocessor = nullptr;

726 LangOpts = nullptr;

727 }

728}

729

733

735 return;

736

738 }

739

740#ifndef NDEBUG

741

742

743 if (SrcManager) {

747

750

752 if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {

753

754

758 }

759

761 }

762 }

763#endif

764

765

766

767 Buffer->HandleDiagnostic(DiagLevel, Info);

768}

769

770

771

775

776

777 if (SrcManager && &SM != SrcManager)

778 return false;

779

781

782 const char *CommentRaw = SM.getCharacterData(CommentBegin);

783 StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);

784

785 if (C.empty())

786 return false;

787

788

789 size_t loc = C.find('\\');

790 if (loc == StringRef::npos) {

792 return false;

793 }

794

795 std::string C2;

796 C2.reserve(C.size());

797

798 for (size_t last = 0;; loc = C.find('\\', last)) {

799 if (loc == StringRef::npos || loc == C.size()) {

800 C2 += C.substr(last);

801 break;

802 }

803 C2 += C.substr(last, loc-last);

804 last = loc + 1;

805

806 if (C[last] == '\n' || C[last] == '\r') {

807 ++last;

808

809

810 if (last < C.size())

811 if (C[last] == '\n' || C[last] == '\r')

812 if (C[last] != C[last-1])

813 ++last;

814 } else {

815

816 C2 += '\\';

817 }

818 }

819

820 if (!C2.empty())

821 ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status, *Markers);

822 return false;

823}

824

825#ifndef NDEBUG

826

827

828

829

830

833

835 return false;

836

837

838 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);

839 Lexer RawLex(FID, FromFile, SM, LangOpts);

840

841

843

845 Tok.setKind(tok::comment);

848 while (Tok.isNot(tok::eof)) {

850 if (!Tok.is(tok::comment)) continue;

851

852 std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);

853 if (Comment.empty()) continue;

854

855

857

858

860 Status, Markers))

861 return true;

862 }

863 return false;

864}

865#endif

866

867

868

872 const char *Kind) {

873 if (diag_begin == diag_end) return 0;

874

876 llvm::raw_svector_ostream OS(Fmt);

878 if (I->first.isInvalid() || !SourceMgr)

879 OS << "\n (frontend)";

880 else {

881 OS << "\n ";

884 OS << " File " << File->getName();

886 }

887 OS << ": " << I->second;

888 }

889

891 std::string KindStr = Prefix + "-" + Kind;

893 << KindStr << true << OS.str();

894 return std::distance(diag_begin, diag_end);

895}

896

897

898

901 std::vector<Directive *> &DL, const char *Kind) {

902 if (DL.empty())

903 return 0;

904

906 llvm::raw_svector_ostream OS(Fmt);

907 for (const auto *D : DL) {

908 if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)

909 OS << "\n File *";

910 else

911 OS << "\n File " << SourceMgr.getFilename(D->DiagnosticLoc);

912 if (D->MatchAnyLine)

913 OS << " Line *";

914 else

916 if (D->DirectiveLoc != D->DiagnosticLoc)

917 OS << " (directive at "

918 << SourceMgr.getFilename(D->DirectiveLoc) << ':'

920 OS << ": " << D->Text;

921 }

922

924 std::string KindStr = Prefix + "-" + Kind;

926 << KindStr << false << OS.str();

927 return DL.size();

928}

929

930

933 while (DiagnosticLoc.isMacroID())

934 DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);

935

936 if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))

937 return true;

938

939 const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));

940 if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))

941 return true;

942

943 return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));

944}

945

946

947

949 const char *Label,

953 bool IgnoreUnexpected) {

954 std::vector<Directive *> LeftOnly;

955 DiagList Right(d2_begin, d2_end);

956

957 for (auto &Owner : Left) {

960

961 for (unsigned i = 0; i < D.Max; ++i) {

962 DiagList::iterator II, IE;

963 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {

964 if (D.MatchAnyLine) {

966 if (LineNo1 != LineNo2)

967 continue;

968 }

969

970 if (D.DiagnosticLoc.isInvalid() && D.MatchAnyFileAndLine &&

972 continue;

973

974 const std::string &RightText = II->second;

975 if (D.match(RightText))

976 break;

977 }

978 if (II == IE) {

979

980 if (i >= D.Min) break;

981 LeftOnly.push_back(&D);

982 } else {

983

984 Right.erase(II);

985 }

986 }

987 }

988

990 if (!IgnoreUnexpected)

991 num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);

992 return num;

993}

994

995

996

997

1001

1002

1003

1004

1005

1006 unsigned NumProblems = 0;

1007

1010

1011

1012 NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,

1015

1016

1020

1021

1022 NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,

1025

1026

1027 NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,

1030

1031 return NumProblems;

1032}

1033

1037

1038 setSourceManager(SM);

1039

1040#ifndef NDEBUG

1042 return;

1043

1045

1047

1048 UnparsedFiles.erase(FID);

1049 ParsedFiles.insert(std::make_pair(FID, FE ? &FE->getFileEntry() : nullptr));

1050 } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {

1051

1052

1053

1054 bool FoundDirectives;

1056 FoundDirectives = false;

1057 else

1058 FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);

1059

1060

1061 UnparsedFiles.insert(std::make_pair(FID,

1062 UnparsedFileStatus(FE, FoundDirectives)));

1063 }

1064#endif

1065}

1066

1067void VerifyDiagnosticConsumer::CheckDiagnostics() {

1068

1070 std::unique_ptr Owner = Diags.takeClient();

1071 Diags.setClient(PrimaryClient, false);

1072

1073#ifndef NDEBUG

1074

1075

1076

1077

1078

1079

1080 if (!UnparsedFiles.empty()) {

1081

1083 for (const auto &I : ParsedFiles)

1084 if (const FileEntry *FE = I.second)

1085 ParsedFileCache.insert(FE);

1086

1087

1088 for (const auto &I : UnparsedFiles) {

1089 const UnparsedFileStatus &Status = I.second;

1091

1092

1093 if (FE && ParsedFileCache.count(*FE))

1094 continue;

1095

1096

1097 if (Status.foundDirectives()) {

1098 llvm::report_fatal_error("-verify directives found after rather"

1099 " than during normal parsing of " +

1100 (FE ? FE->getName() : "(unknown)"));

1101 }

1102 }

1103

1104

1105 UnparsedFiles.clear();

1106 }

1107#endif

1108

1109 if (SrcManager) {

1110

1111

1117 }

1118

1119

1121 } else {

1123 ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();

1126 Buffer->err_end(), "error");

1129 Buffer->warn_end(), "warn");

1132 Buffer->remark_end(), "remark");

1135 Buffer->note_end(), "note");

1136 }

1137

1138 Diags.setClient(CurClient, Owner.release() != nullptr);

1139

1140

1143}

1144

1148 bool MatchAnyFileAndLine,

1149 bool MatchAnyLine, StringRef Text,

1150 unsigned Min, unsigned Max) {

1151 if (!RegexKind)

1152 return std::make_unique(DirectiveLoc, DiagnosticLoc,

1153 MatchAnyFileAndLine,

1155

1156

1157 std::string RegexStr;

1158 StringRef S = Text;

1159 while (!S.empty()) {

1160 if (S.consume_front("{{")) {

1161 size_t RegexMatchLength = S.find("}}");

1162 assert(RegexMatchLength != StringRef::npos);

1163

1164 RegexStr += "(";

1165 RegexStr.append(S.data(), RegexMatchLength);

1166 RegexStr += ")";

1167 S = S.drop_front(RegexMatchLength + 2);

1168 } else {

1169 size_t VerbatimMatchLength = S.find("{{");

1170 if (VerbatimMatchLength == StringRef::npos)

1171 VerbatimMatchLength = S.size();

1172

1173 RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));

1174 S = S.drop_front(VerbatimMatchLength);

1175 }

1176 }

1177

1178 return std::make_unique(DirectiveLoc, DiagnosticLoc,

1179 MatchAnyFileAndLine, MatchAnyLine,

1181}

Defines the Diagnostic-related interfaces.

Defines the clang::FileManager interface and associated types.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

llvm::MachO::FileType FileType

Defines the PPCallbacks interface.

Defines the clang::Preprocessor interface.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

Defines the clang::TokenKind enum and support functions.

static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, const_diag_iterator d2_end, bool IgnoreUnexpected)

CheckLists - Compare expected to seen diagnostic lists and return the the difference between them.

static bool findDirectives(SourceManager &SM, FileID FID, const LangOptions &LangOpts)

Lex the specified source file to determine whether it contains any expected-* directives.

TextDiagnosticBuffer::const_iterator const_diag_iterator

TextDiagnosticBuffer::DiagList DiagList

static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc)

Determine whether two source locations come from the same file.

VerifyDiagnosticConsumer::DirectiveList DirectiveList

static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, ExpectedData &ED)

CheckResults - This compares the expected results to those that were actually reported.

static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr, const_diag_iterator diag_begin, const_diag_iterator diag_end, const char *Kind)

Takes a list of diagnostics that have been generated but not matched by an expected-* directive and p...

VerifyDiagnosticConsumer::Directive Directive

static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::DirectiveStatus &Status, VerifyDiagnosticConsumer::MarkerTracker &Markers)

ParseDirective - Go through the comment and see if it indicates expected diagnostics.

static std::string DetailedErrorString(const DiagnosticsEngine &Diags)

static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr, std::vector< Directive * > &DL, const char *Kind)

Takes a list of diagnostics that were expected to have been generated but were not and produces a dia...

void addDirective(StringRef MarkerName, const UnattachedDirective &UD)

MarkerTracker(DiagnosticsEngine &Diags)

void addMarker(StringRef MarkerName, SourceLocation Pos)

const DiagnosticBuilder & setForceEmit() const

Forces the diagnostic to be emitted.

Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...

virtual void EndSourceFile()

Callback to inform the diagnostic client that processing of a source file has ended.

unsigned NumErrors

Number of errors reported.

virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)

Callback to inform the diagnostic client that processing of a source file is beginning.

std::vector< std::string > VerifyPrefixes

The prefixes for comment directives sought by -verify ("expected" by default).

A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...

const SourceLocation & getLocation() const

SourceManager & getSourceManager() const

bool hasSourceManager() const

Concrete class used by the front-end to report problems and issues.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

bool hasSourceManager() const

DiagnosticOptions & getDiagnosticOptions() const

Retrieve the diagnostic options.

void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)

Set the diagnostic client associated with this diagnostic object.

std::unique_ptr< DiagnosticConsumer > takeClient()

Return the current diagnostic client along with ownership of that client.

SourceManager & getSourceManager() const

Level

The level of the diagnostic, after it has been through mapping.

DiagnosticConsumer * getClient()

bool ownsClient() const

Determine whether this DiagnosticsEngine object own its client.

const FileEntry & getFileEntry() const

StringRef getName() const

The name of this FileEntry.

Cached information about one file (either on disk or in the virtual file system).

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.

bool LexFromRawLexer(Token &Result)

LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...

void SetCommentRetentionState(bool Mode)

SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode.

static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)

getSpelling - This method is used to get the spelling of a token into a preallocated buffer,...

This interface provides a way to observe the actions of the preprocessor as it does its thing.

virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID=FileID())

Callback invoked whenever a source file is entered or exited.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

SourceManager & getSourceManager() const

HeaderSearch & getHeaderSearchInfo() const

OptionalFileEntryRef LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, ConstSearchDirIterator FromDir, const FileEntry *FromFile, ConstSearchDirIterator *CurDir, SmallVectorImpl< char > *SearchPath, SmallVectorImpl< char > *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache=false, bool OpenFile=true, bool CacheFailures=true)

Given a "foo" or reference, look up the indicated file.

DiagnosticsEngine & getDiagnostics() const

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const

FileID getFileID(SourceLocation SpellingLoc) const

Return the FileID for a SourceLocation.

OptionalFileEntryRef getFileEntryRefForID(FileID FID) const

Returns the FileEntryRef for the provided FileID.

bool isLoadedFileID(FileID FID) const

Returns true if FID came from a PCH/Module.

StringRef getFilename(SourceLocation SpellingLoc) const

Return the filename of the file containing a SourceLocation.

SourceLocation getExpansionLoc(SourceLocation Loc) const

Given a SourceLocation object Loc, return the expansion location referenced by the ID.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

DiagList::const_iterator const_iterator

std::vector< std::pair< SourceLocation, std::string > > DiagList

const_iterator warn_end() const

const_iterator note_begin() const

const_iterator err_begin() const

const_iterator note_end() const

const_iterator warn_begin() const

const_iterator remark_begin() const

const_iterator remark_end() const

const_iterator err_end() const

Token - This structure provides full information about a lexed token.

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

void setKind(tok::TokenKind K)

bool is(tok::TokenKind K) const

is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....

bool isNot(tok::TokenKind K) const

Directive - Abstract class representing a parsed verify directive.

virtual bool isValid(std::string &Error)=0

static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)

static const unsigned MaxCount

Constant representing n or more matches.

virtual bool match(StringRef S)=0

VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...

void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS)

Update lists of parsed and unparsed files.

VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)

Create a new verifying diagnostic client, which will issue errors to the currently-attached diagnosti...

@ IsUnparsed

File has diagnostics and may have directives.

@ IsUnparsedNoDirectives

File has diagnostics but guaranteed no directives.

@ IsParsed

File has been processed via HandleComment.

void EndSourceFile() override

Callback to inform the diagnostic client that processing of a source file has ended.

void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override

Callback to inform the diagnostic client that processing of a source file is beginning.

std::vector< std::unique_ptr< Directive > > DirectiveList

~VerifyDiagnosticConsumer() override

@ HasExpectedNoDiagnostics

@ HasNoDirectivesReported

@ HasOtherExpectedDirectives

bool HandleComment(Preprocessor &PP, SourceRange Comment) override

HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...

void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override

Handle this diagnostic, reporting it to the user or capturing it to a log as needed.

CharacteristicKind

Indicates whether a file or directory holds normal user code, system code, or system code which is im...

The JSON file list parser is used to communicate input to InstallAPI.

DiagnosticLevelMask

A bitmask representing the diagnostic levels used by VerifyDiagnosticConsumer.

@ DType

'dtype' clause, an alias for 'device_type', stored separately for diagnostic purposes.

LLVM_READONLY bool isLetter(unsigned char c)

Return true if this character is an ASCII letter: [a-zA-Z].

LLVM_READONLY bool isAlphanumeric(unsigned char c)

Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].

LLVM_READONLY bool isDigit(unsigned char c)

Return true if this character is an ASCII digit: [0-9].

LLVM_READONLY bool isWhitespace(unsigned char c)

Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...

ExpectedData - owns directive objects and deletes on destructor.