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 && (*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 ( && 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')
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 (.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.