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) {
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 (->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 (.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 ( && 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 {
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 (; .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')
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 (.MatchAnyLine) {
966 if (LineNo1 != LineNo2)
967 continue;
968 }
969
970 if (.DiagnosticLoc.isInvalid() &&
.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.