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

1

2

3

4

5

6

7

8

9

10

11

12

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

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

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

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

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

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

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

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

36#include

37#include

38#include

39#include

40#include

41#include

42#include

43#include

44#include

45

46using namespace clang;

47

51

52#ifndef NDEBUG

53

54namespace {

55

56class VerifyFileTracker : public PPCallbacks {

59

60public:

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

63

64

65

66 void FileChanged(SourceLocation Loc, FileChangeReason Reason,

68 FileID PrevFID) override {

71 }

72};

73

74}

75

76#endif

77

78

79

80

81

84

85namespace {

86

87

88class StandardDirective : public Directive {

89public:

91 StringRef Spelling, bool MatchAnyFileAndLine,

92 bool MatchAnyLine, StringRef Text, unsigned Min,

93 unsigned Max)

94 : Directive(DirectiveLoc, DiagnosticLoc, Spelling, 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 StringRef Spelling, bool MatchAnyFileAndLine,

110 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,

111 StringRef RegexStr)

112 : Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,

114 Regex(RegexStr) {}

115

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

118 }

119

120 bool match(StringRef S) override {

121 return Regex.match(S);

122 }

123

124private:

125 llvm::Regex Regex;

126};

127

128class ParseHelper

129{

130public:

131 ParseHelper(StringRef S)

132 : Begin(S.begin()), End(S.end()), C(Begin), P(Begin) {}

133

134

135 bool Next(StringRef S) {

136 P = C;

137 PEnd = C + S.size();

138 if (PEnd > End)

139 return false;

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

141 }

142

143

144

145 bool Next(unsigned &N) {

146 unsigned TMP = 0;

147 P = C;

148 PEnd = P;

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

150 TMP *= 10;

151 TMP += *PEnd - '0';

152 }

153 if (PEnd == C)

154 return false;

155 N = TMP;

156 return true;

157 }

158

159

160

161 bool NextMarker() {

162 P = C;

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

164 return false;

165 PEnd = P;

166 ++PEnd;

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

168 PEnd < End)

169 ++PEnd;

170 return PEnd > P + 1;

171 }

172

173

174

175

176

177

178

179

180

181

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

183 bool FinishDirectiveToken = false) {

184 do {

185 if (!S.empty()) {

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

187 PEnd = P + S.size();

188 }

189 else {

190 P = C;

191 while (P != End && isLetter(*P))

192 ++P;

193 PEnd = P + 1;

194 }

195 if (P == End)

196 break;

197

198 if (EnsureStartOfWord

199

201

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

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

204 continue;

205 if (FinishDirectiveToken) {

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

208 ++PEnd;

209

210

211

212

213

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

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

216 --PEnd;

217 }

218 return true;

219 } while (Advance());

220 return false;

221 }

222

223

224

225 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {

226 unsigned Depth = 1;

227 P = C;

228 while (P < End) {

229 StringRef S(P, End - P);

230 if (S.starts_with(OpenBrace)) {

231 ++Depth;

232 P += OpenBrace.size();

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

234 --Depth;

235 if (Depth == 0) {

236 PEnd = P + CloseBrace.size();

237 return true;

238 }

239 P += CloseBrace.size();

240 } else {

241 ++P;

242 }

243 }

244 return false;

245 }

246

247

248

249 bool Advance() {

250 C = PEnd;

251 return C < End;

252 }

253

254

255

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

257

258

259 void SkipWhitespace() {

261 ;

262 }

263

264

265 bool Done() {

266 return !(C < End);

267 }

268

269

270 const char * const Begin;

271

272

273 const char * const End;

274

275

276 const char *C;

277

278

279 const char *P;

280

281private:

282

283 const char *PEnd = nullptr;

284};

285

286

287struct UnattachedDirective {

289 std::string Spelling;

290 bool RegexKind = false;

292 std::string Text;

293 unsigned Min = 1, Max = 1;

294};

295

296

297

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

300 bool MatchAnyFileAndLine = false,

301 bool MatchAnyLine = false) {

302

304 UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,

305 MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max);

306

307 std::string Error;

308 if (!D->isValid(Error)) {

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

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

311 }

312

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

314}

315

316}

317

318

319

320

321

322

323

324

325

326

327

330

331 struct Marker {

335 };

336 llvm::StringMap Markers;

337

338

339

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

341

342public:

344

345

347 auto InsertResult = Markers.insert(

349

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

351 if (!InsertResult.second) {

352

353 M.RedefLoc = Pos;

354 } else {

355

356 auto Deferred = DeferredDirectives.find(MarkerName);

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

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

360 M.UseLoc = UD.DirectivePos;

361 attachDirective(Diags, UD, Pos);

362 }

363 DeferredDirectives.erase(Deferred);

364 }

365 }

366 }

367

368

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

370 auto MarkerIt = Markers.find(MarkerName);

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

372 Marker &M = MarkerIt->second;

374 M.UseLoc = UD.DirectivePos;

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

376 }

377 DeferredDirectives[MarkerName].push_back(UD);

378 }

379

380

381

383 for (auto &MarkerInfo : Markers) {

384 StringRef Name = MarkerInfo.first();

385 Marker &M = MarkerInfo.second;

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

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

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

390 }

391 }

392

393 for (auto &DeferredPair : DeferredDirectives) {

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

395 diag::err_verify_no_such_marker)

396 << DeferredPair.first();

397 }

398 }

399};

400

403 return "expected";

405}

406

407

408

409

410

416

417

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

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

420 break;

421 PH.C = PH.P;

422 if (!PH.NextMarker()) {

423 PH.Next("#");

424 PH.Advance();

425 continue;

426 }

427 PH.Advance();

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

429 }

430

431

432 bool FoundDirective = false;

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

434

435

436

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

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

440 break;

441

442 StringRef DToken = PH.Match();

443 PH.Advance();

444

445 UnattachedDirective D;

446 D.Spelling = DToken;

447

448 const char *KindStr = "string";

449

450

451

452

453

454

455

456

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

458 D.RegexKind = true;

459 KindStr = "regex";

460 }

461

462

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

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

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

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

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

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

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

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

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

475 if (D.RegexKind)

476 continue;

477 } else

478 continue;

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

480

481

482

483

484 if (!llvm::binary_search(Prefixes, DToken))

485 continue;

486

488 if (State.Status ==

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

491 << D.Spelling << true;

492 } else if (State.Status !=

495 State.FirstNoDiagnosticsDirective = D.Spelling;

496 }

497 continue;

498 }

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

501 << D.Spelling << false

502 << State.FirstNoDiagnosticsDirective;

503 continue;

504 }

506

507

508

509 if (!D.DL)

510 return true;

511

512

514 StringRef Marker;

515 bool MatchAnyFileAndLine = false;

516 bool MatchAnyLine = false;

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

518 ExpectedLoc = Pos;

519 } else {

520 PH.Advance();

521 unsigned Line = 0;

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

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

524

525 PH.Advance();

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

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

529 if (FoundPlus) ExpectedLine += Line;

530 else ExpectedLine -= Line;

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

532 }

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

534

535 if (Line > 0)

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

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

538 Marker = PH.Match();

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

540

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

542 PH.Advance();

543

544 if (Filename == "*") {

545 MatchAnyFileAndLine = true;

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

548 diag::err_verify_missing_line)

549 << "'*'";

550 continue;

551 }

552 MatchAnyLine = true;

554 } else {

555

557 PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,

558 nullptr, nullptr, nullptr, nullptr, nullptr);

561 diag::err_verify_missing_file)

562 << Filename << KindStr;

563 continue;

564 }

565

569

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

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

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

573 MatchAnyLine = true;

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

575 }

576 }

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

578 MatchAnyLine = true;

580 }

581

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

584 diag::err_verify_missing_line) << KindStr;

585 continue;

586 }

587 PH.Advance();

588 }

589

590

591 PH.SkipWhitespace();

592

593

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

595 PH.Advance();

596

597

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

600 PH.Advance();

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

602 PH.Advance();

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

605 diag::err_verify_invalid_range) << KindStr;

606 continue;

607 }

608 PH.Advance();

609 } else {

610 D.Max = D.Min;

611 }

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

613

615 PH.Advance();

616 }

617

618

619 PH.SkipWhitespace();

620

621

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

624 diag::err_verify_missing_start) << KindStr;

625 continue;

626 }

628 const char *const DelimBegin = PH.C;

629 PH.Advance();

630

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

632 CloseBrace += '}';

633 const char* const ContentBegin = PH.C;

634

635 StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);

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

638 diag::err_verify_missing_end)

639 << KindStr << CloseBrace;

640 continue;

641 }

642 const char* const ContentEnd = PH.P;

643 PH.Advance();

644

645 D.DirectivePos = Pos;

646 D.ContentBegin = Pos.getLocWithOffset(ContentBegin - PH.Begin);

647

648

649 StringRef NewlineStr = "\\n";

650 StringRef Content(ContentBegin, ContentEnd-ContentBegin);

651 size_t CPos = 0;

652 size_t FPos;

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

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

655 D.Text += '\n';

656 CPos = FPos + NewlineStr.size();

657 }

658 if (D.Text.empty())

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

660

661

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

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

664 return false;

665 }

666

667 if (Marker.empty())

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

669 else

671 FoundDirective = true;

672 }

673

674 return FoundDirective;

675}

676

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

679 PrimaryClientOwner(Diags.takeClient()),

682 if (Diags.hasSourceManager())

683 setSourceManager(Diags.getSourceManager());

684}

685

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

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

689 SrcManager = nullptr;

690 CheckDiagnostics();

691 assert(!Diags.ownsClient() &&

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

693}

694

695

696

699

700 if (++ActiveSourceFiles == 1) {

701 if (PP) {

702 CurrentPreprocessor = PP;

703 this->LangOpts = &LangOpts;

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

706#ifndef NDEBUG

707

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

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

710#endif

711 }

712 }

713

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

715 PrimaryClient->BeginSourceFile(LangOpts, PP);

716}

717

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

720 PrimaryClient->EndSourceFile();

721

722

723 if (--ActiveSourceFiles == 0) {

724 if (CurrentPreprocessor)

725 const_cast<Preprocessor *>(CurrentPreprocessor)->

726 removeCommentHandler(this);

727

728

729 Markers->finalize();

730

731

732 CheckDiagnostics();

733 CurrentPreprocessor = nullptr;

734 LangOpts = nullptr;

735 }

736}

737

741

743 return;

744

746 }

747

748#ifndef NDEBUG

749

750

751 if (SrcManager) {

755

756 Loc = SrcManager->getExpansionLoc(Loc);

757 FileID FID = SrcManager->getFileID(Loc);

758

759 auto FE = SrcManager->getFileEntryRefForID(FID);

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

761

762

763 HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();

766 }

767

769 }

770 }

771#endif

772

773

774

775 Buffer->HandleDiagnostic(DiagLevel, Info);

776}

777

778

779

783

784

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

786 return false;

787

789

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

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

792

793 if (C.empty())

794 return false;

795

796

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

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

800 return false;

801 }

802

803 std::string C2;

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

805

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

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

808 C2 += C.substr(last);

809 break;

810 }

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

812 last = loc + 1;

813

814 if (last < C.size() && (C[last] == '\n' || C[last] == '\r')) {

815 ++last;

816

817

818 if (last < C.size())

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

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

821 ++last;

822 } else {

823

824 C2 += '\\';

825 }

826 }

827

828 if (!C2.empty())

829 ParseDirective(C2, &ED, SM, &PP, CommentBegin, State, *Markers);

830 return false;

831}

832

833#ifndef NDEBUG

834

835

836

837

838

841

843 return false;

844

845

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

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

848

849

851

853 Tok.setKind(tok::comment);

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

858 if (Tok.is(tok::comment)) continue;

859

861 if (Comment.empty()) continue;

862

863

865

866

867 if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(), State,

868 Markers))

869 return true;

870 }

871 return false;

872}

873#endif

874

875

876

880 const char *Kind) {

881 if (diag_begin == diag_end) return 0;

882

884 llvm::raw_svector_ostream OS(Fmt);

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

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

888 else {

889 OS << "\n ";

891 SourceMgr->getFileEntryRefForID(SourceMgr->getFileID(I->first)))

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

893 OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);

894 }

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

896 }

897

898 const bool IsSinglePrefix =

902 << IsSinglePrefix << Prefix << Kind << true << OS.str();

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

904}

905

906

907

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

911 if (DL.empty())

912 return 0;

913

914 const bool IsSinglePrefix =

916

918 llvm::raw_svector_ostream OS(Fmt);

919 for (const auto *D : DL) {

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

921 OS << "\n File *";

922 else

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

924 if (D->MatchAnyLine)

925 OS << " Line *";

926 else

927 OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);

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

929 OS << " (directive at "

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

931 << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';

932 if (!IsSinglePrefix)

933 OS << " \'" << D->Spelling << '\'';

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

935 }

936

939 << IsSinglePrefix << Prefix << Kind << false << OS.str();

940 return DL.size();

941}

942

943

946 while (DiagnosticLoc.isMacroID())

947 DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);

948

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

950 return true;

951

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

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

954 return true;

955

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

957}

958

959

960

962 const char *Label,

966 bool IgnoreUnexpected) {

967 std::vector<Directive *> LeftOnly;

968 DiagList Right(d2_begin, d2_end);

969

970 for (auto &Owner : Left) {

972 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);

973

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

975 DiagList::iterator II, IE;

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

978 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);

979 if (LineNo1 != LineNo2)

980 continue;

981 }

982

985 continue;

986

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

988 if (D.match(RightText))

989 break;

990 }

991 if (II == IE) {

992

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

994 LeftOnly.push_back(&D);

995 } else {

996

997 Right.erase(II);

998 }

999 }

1000 }

1001

1002 unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);

1003 if (!IgnoreUnexpected)

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

1005 return num;

1006}

1007

1008

1009

1010

1014

1015

1016

1017

1018

1019 unsigned NumProblems = 0;

1020

1023

1024

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

1028

1029

1033

1034

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

1038

1039

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

1043

1044 return NumProblems;

1045}

1046

1050

1051 setSourceManager(SM);

1052

1053#ifndef NDEBUG

1055 return;

1056

1058

1060

1061 UnparsedFiles.erase(FID);

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

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

1064

1065

1066

1067 bool FoundDirectives;

1069 FoundDirectives = false;

1070 else

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

1072

1073

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

1075 UnparsedFileStatus(FE, FoundDirectives)));

1076 }

1077#endif

1078}

1079

1080void VerifyDiagnosticConsumer::CheckDiagnostics() {

1081

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

1084 Diags.setClient(PrimaryClient, false);

1085

1086#ifndef NDEBUG

1087

1088

1089

1090

1091

1092

1093 if (!UnparsedFiles.empty()) {

1094

1096 for (const auto &I : ParsedFiles)

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

1098 ParsedFileCache.insert(FE);

1099

1100

1101 for (const auto &I : UnparsedFiles) {

1102 const UnparsedFileStatus &Status = I.second;

1104

1105

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

1107 continue;

1108

1109

1110 if (Status.foundDirectives()) {

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

1112 " than during normal parsing of " +

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

1114 }

1115 }

1116

1117

1118 UnparsedFiles.clear();

1119 }

1120#endif

1121

1122 if (SrcManager) {

1123

1124

1126 Diags.Report(diag::err_verify_no_directives).setForceEmit()

1130 }

1131

1132

1134 } else {

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

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

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

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

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

1149 }

1150

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

1152

1153

1154 Buffer.reset(new TextDiagnosticBuffer());

1155 ED.Reset();

1156}

1157

1158std::unique_ptr

1162 unsigned Min, unsigned Max) {

1163 if (!RegexKind)

1167

1168

1169 std::string RegexStr;

1170 StringRef S = Text;

1171 while (!S.empty()) {

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

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

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

1175

1176 RegexStr += "(";

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

1178 RegexStr += ")";

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

1180 } else {

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

1182 if (VerbatimMatchLength == StringRef::npos)

1183 VerbatimMatchLength = S.size();

1184

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

1186 S = S.drop_front(VerbatimMatchLength);

1187 }

1188 }

1189

1193}

Defines the Diagnostic-related interfaces.

FormatToken * Next

The next token in the unwrapped line.

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.

Definition VerifyDiagnosticConsumer.cpp:961

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

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

Definition VerifyDiagnosticConsumer.cpp:839

TextDiagnosticBuffer::const_iterator const_diag_iterator

Definition VerifyDiagnosticConsumer.cpp:83

TextDiagnosticBuffer::DiagList DiagList

Definition VerifyDiagnosticConsumer.cpp:82

VerifyDiagnosticConsumer::ExpectedData ExpectedData

Definition VerifyDiagnosticConsumer.cpp:50

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

Determine whether two source locations come from the same file.

Definition VerifyDiagnosticConsumer.cpp:944

VerifyDiagnosticConsumer::DirectiveList DirectiveList

Definition VerifyDiagnosticConsumer.cpp:49

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

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

Definition VerifyDiagnosticConsumer.cpp:1011

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

Definition VerifyDiagnosticConsumer.cpp:877

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

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

Definition VerifyDiagnosticConsumer.cpp:411

VerifyDiagnosticConsumer::Directive Directive

Definition VerifyDiagnosticConsumer.cpp:48

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

Definition VerifyDiagnosticConsumer.cpp:401

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

Definition VerifyDiagnosticConsumer.cpp:908

void finalize()

Definition VerifyDiagnosticConsumer.cpp:382

void addDirective(StringRef MarkerName, const UnattachedDirective &UD)

Definition VerifyDiagnosticConsumer.cpp:369

MarkerTracker(DiagnosticsEngine &Diags)

Definition VerifyDiagnosticConsumer.cpp:343

void addMarker(StringRef MarkerName, SourceLocation Pos)

Definition VerifyDiagnosticConsumer.cpp:346

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

unsigned NumErrors

Number of errors reported.

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.

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.

Level

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

DiagnosticConsumer * getClient()

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.

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

SourceManager & getSourceManager() 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.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

DiagList::const_iterator const_iterator

const_iterator warn_end() const

const_iterator note_begin() const

const_iterator err_begin() const

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

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.

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, StringRef Spelling, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)

Definition VerifyDiagnosticConsumer.cpp:1159

static const unsigned MaxCount

Constant representing n or more matches.

const std::string Spelling

virtual bool match(StringRef S)=0

SourceLocation DiagnosticLoc

SourceLocation DirectiveLoc

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.

Definition VerifyDiagnosticConsumer.cpp:1047

VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)

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

Definition VerifyDiagnosticConsumer.cpp:677

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

Definition VerifyDiagnosticConsumer.cpp:718

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

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

Definition VerifyDiagnosticConsumer.cpp:697

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

~VerifyDiagnosticConsumer() override

Definition VerifyDiagnosticConsumer.cpp:686

@ HasExpectedNoDiagnostics

@ HasNoDirectivesReported

@ HasOtherExpectedDirectives

bool HandleComment(Preprocessor &PP, SourceRange Comment) override

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

Definition VerifyDiagnosticConsumer.cpp:780

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.

Definition VerifyDiagnosticConsumer.cpp:738

CharacteristicKind

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

SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)

Returns the results of matching Matcher on Node.

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

@ Match

This is not an overload because the signature exactly matches an existing declaration.

CustomizableOptional< FileEntryRef > OptionalFileEntryRef

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.