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"
62 : Verify(Verify),
SM(
SM) {}
88class StandardDirective :
public Directive {
91 StringRef Spelling,
bool MatchAnyFileAndLine,
92 bool MatchAnyLine, StringRef
Text,
unsigned Min,
93 unsigned Max,
bool FullMatchRequired)
94 :
Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
95 MatchAnyLine,
Text,
Min,
Max, FullMatchRequired) {}
97 bool isValid(std::string &
Error)
override {
103 if (!S.contains(
Text)) {
106 if (!FullMatchRequired) {
118 StringRef Spelling,
bool MatchAnyFileAndLine,
119 bool MatchAnyLine, StringRef
Text,
unsigned Min,
unsigned Max,
120 StringRef RegexStr,
bool FullMatchRequired)
121 :
Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
122 MatchAnyLine,
Text,
Min,
Max, FullMatchRequired),
125 bool isValid(std::string &
Error)
override {
130 if (!FullMatchRequired) {
136 llvm::StringRef TrimmedText = S.trim();
137 Regex.match(TrimmedText, &Matches);
138 if (Matches.empty()) {
141 return Matches[0].size() == TrimmedText.size()
153 ParseHelper(StringRef S)
154 : Begin(S.begin()), End(S.end()),
C(Begin), P(Begin) {}
157 bool Next(StringRef S) {
162 return memcmp(P, S.data(), S.size()) == 0;
167 bool Next(
unsigned &N) {
171 for (; PEnd < End && *PEnd >=
'0' && *PEnd <=
'9'; ++PEnd) {
185 if (P == End || *P !=
'#')
204 bool Search(StringRef S,
bool EnsureStartOfWord =
false,
205 bool FinishDirectiveToken =
false) {
208 P = std::search(
C, End, S.begin(), S.end());
220 if (EnsureStartOfWord
224 || (P > (Begin + 1) && (P[-1] ==
'/' || P[-1] ==
'*')
227 if (FinishDirectiveToken) {
229 || *PEnd ==
'-' || *PEnd ==
'_'))
236 assert(
isLetter(*P) &&
"-verify prefix must start with a letter");
237 while (
isDigit(PEnd[-1]) || PEnd[-1] ==
'-')
247 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
251 StringRef S(P, End - P);
252 if (S.starts_with(OpenBrace)) {
254 P += OpenBrace.size();
255 }
else if (S.starts_with(CloseBrace)) {
258 PEnd = P + CloseBrace.size();
261 P += CloseBrace.size();
278 StringRef
Match() {
return StringRef(P, PEnd - P); }
281 void SkipWhitespace() {
292 const char *
const Begin;
295 const char *
const End;
305 const char *PEnd =
nullptr;
309struct UnattachedDirective {
311 std::string Spelling;
312 bool RegexKind =
false;
315 unsigned Min = 1,
Max = 1;
322 bool MatchAnyFileAndLine =
false,
323 bool MatchAnyLine =
false) {
325 std::unique_ptr<Directive> D =
327 MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min,
331 if (!D->isValid(
Error)) {
332 Diags.
Report(UD.ContentBegin, diag::err_verify_invalid_content)
333 << (UD.RegexKind ?
"regex" :
"string") <<
Error;
336 UD.DL->push_back(std::move(D));
359 llvm::StringMap<Marker> Markers;
363 llvm::StringMap<llvm::SmallVector<UnattachedDirective, 2>> DeferredDirectives;
370 auto InsertResult = Markers.insert(
373 Marker &M = InsertResult.first->second;
374 if (!InsertResult.second) {
379 auto Deferred = DeferredDirectives.find(MarkerName);
380 if (Deferred != DeferredDirectives.end()) {
381 for (
auto &UD : Deferred->second) {
383 M.UseLoc = UD.DirectivePos;
384 attachDirective(Diags, UD, Pos);
386 DeferredDirectives.erase(Deferred);
392 void addDirective(StringRef MarkerName,
const UnattachedDirective &UD) {
393 auto MarkerIt = Markers.find(MarkerName);
394 if (MarkerIt != Markers.end()) {
395 Marker &M = MarkerIt->second;
397 M.UseLoc = UD.DirectivePos;
398 return attachDirective(Diags, UD, M.DefLoc);
400 DeferredDirectives[MarkerName].push_back(UD);
406 for (
auto &MarkerInfo : Markers) {
407 StringRef Name = MarkerInfo.first();
408 Marker &M = MarkerInfo.second;
410 Diags.Report(M.UseLoc, diag::err_verify_ambiguous_marker) << Name;
411 Diags.Report(M.DefLoc, diag::note_verify_ambiguous_marker) << Name;
412 Diags.Report(M.RedefLoc, diag::note_verify_ambiguous_marker) << Name;
416 for (
auto &DeferredPair : DeferredDirectives) {
417 Diags.Report(DeferredPair.second.front().DirectivePos,
418 diag::err_verify_no_such_marker)
419 << DeferredPair.first();
438 bool OneDiagPerDirective,
439 bool DisableWildcardInDiagLoc) {
443 for (ParseHelper PH(S); !PH.Done();) {
444 if (!PH.Search(
"#",
true))
447 if (!PH.NextMarker()) {
457 bool FoundDirective =
false;
458 for (ParseHelper PH(S); !PH.Done();) {
463 if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(),
true,
true)
464 : PH.Search(
"",
true,
true)))
467 StringRef DToken = PH.Match();
470 UnattachedDirective D;
473 const char *KindStr =
"string";
482 if (DToken.consume_back(
"-re")) {
490 if (DToken.ends_with(
DType =
"-error"))
491 D.DL = ED ? &ED->
Errors :
nullptr;
492 else if (DToken.ends_with(
DType =
"-warning"))
493 D.DL = ED ? &ED->
Warnings :
nullptr;
494 else if (DToken.ends_with(
DType =
"-remark"))
495 D.DL = ED ? &ED->
Remarks :
nullptr;
496 else if (DToken.ends_with(
DType =
"-note"))
497 D.DL = ED ? &ED->
Notes :
nullptr;
498 else if (DToken.ends_with(
DType =
"-no-diagnostics")) {
504 DToken = DToken.substr(0, DToken.size()-
DType.size());
509 if (!llvm::binary_search(Prefixes, DToken))
515 Diags.
Report(Pos, diag::err_verify_invalid_no_diags)
516 << D.Spelling <<
true;
517 }
else if (State.Status !=
520 State.FirstNoDiagnosticsDirective = D.Spelling;
525 Diags.
Report(Pos, diag::err_verify_invalid_no_diags)
526 << D.Spelling <<
false
527 << State.FirstNoDiagnosticsDirective;
540 bool MatchAnyFileAndLine =
false;
541 bool MatchAnyLine =
false;
548 StringRef CurrentBufferName =
549 SM.getBufferOrFake(
SM.getFileID(Pos)).getBufferIdentifier();
550 if (CurrentBufferName.starts_with(
"input_line_"))
551 MatchAnyFileAndLine =
true;
556 bool FoundPlus = PH.Next(
"+");
557 if (FoundPlus || PH.Next(
"-")) {
561 unsigned ExpectedLine =
SM.getSpellingLineNumber(Pos, &
Invalid);
563 if (FoundPlus) ExpectedLine +=
Line;
564 else ExpectedLine -=
Line;
565 ExpectedLoc =
SM.translateLineCol(
SM.getFileID(Pos), ExpectedLine, 1);
567 }
else if (PH.Next(
Line)) {
570 ExpectedLoc =
SM.translateLineCol(
SM.getFileID(Pos),
Line, 1);
571 }
else if (PH.NextMarker()) {
573 }
else if (PP && PH.Search(
":")) {
575 StringRef Filename(PH.C, PH.P-PH.C);
578 if (Filename ==
"*") {
579 if (DisableWildcardInDiagLoc) {
581 diag::err_verify_wildcard_loc);
582 State.WildcardsAreErroneouslyPresent =
true;
584 MatchAnyFileAndLine =
true;
587 diag::err_verify_missing_line)
596 Filename.starts_with(
"input_line_")) {
598 File =
SM.getFileManager().getOptionalFileRef(Filename);
602 PP->
LookupFile(Pos, Filename,
false,
nullptr,
nullptr,
nullptr,
603 nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
607 diag::err_verify_missing_file)
608 << Filename << KindStr;
617 ExpectedLoc =
SM.translateLineCol(FID,
Line, 1);
618 else if (PH.Next(
"*")) {
619 if (DisableWildcardInDiagLoc) {
621 diag::err_verify_wildcard_loc);
622 State.WildcardsAreErroneouslyPresent =
true;
625 ExpectedLoc =
SM.translateLineCol(FID, 1, 1);
628 }
else if (PH.Next(
"*")) {
629 if (DisableWildcardInDiagLoc) {
631 diag::err_verify_wildcard_loc);
632 State.WildcardsAreErroneouslyPresent =
true;
638 if (ExpectedLoc.
isInvalid() && !MatchAnyLine && Marker.empty()) {
640 diag::err_verify_missing_line) << KindStr;
649 std::optional<std::ptrdiff_t> NonSingularMatchDiagOffset;
652 if (PH.Next(D.Min)) {
653 if (OneDiagPerDirective && D.Min != 1) {
654 NonSingularMatchDiagOffset = PH.C - PH.Begin;
662 if (OneDiagPerDirective) {
663 NonSingularMatchDiagOffset = PH.C - PH.Begin;
665 }
else if (PH.Next(
"-")) {
667 if (!PH.Next(D.Max) || D.Max < D.Min) {
669 diag::err_verify_invalid_range) << KindStr;
672 if (OneDiagPerDirective && D.Max != 1) {
673 NonSingularMatchDiagOffset = PH.C - PH.Begin;
679 }
else if (PH.Next(
"+")) {
681 if (OneDiagPerDirective) {
682 NonSingularMatchDiagOffset = PH.C - PH.Begin;
688 if (NonSingularMatchDiagOffset) {
690 diag::err_verify_non_singular_match);
691 State.AllDirectivesMatchExactlyOneDiag =
false;
698 if (!PH.Next(
"{{")) {
700 diag::err_verify_missing_start) << KindStr;
704 const char *
const DelimBegin = PH.C;
707 for (; !D.RegexKind && PH.Next(
"{"); PH.Advance())
709 const char*
const ContentBegin = PH.C;
711 StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);
712 if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {
714 diag::err_verify_missing_end)
715 << KindStr << CloseBrace;
718 const char*
const ContentEnd = PH.P;
721 D.DirectivePos = Pos;
725 StringRef NewlineStr =
"\\n";
726 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
729 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
730 D.Text += Content.substr(CPos, FPos-CPos);
732 CPos = FPos + NewlineStr.size();
735 D.Text.assign(ContentBegin, ContentEnd);
738 if (D.RegexKind && D.Text.find(
"{{") == StringRef::npos) {
739 Diags.
Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;
744 attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
747 FoundDirective =
true;
750 return FoundDirective;
754 : Diags(Diags_), PrimaryClient(Diags.getClient()),
755 PrimaryClientOwner(Diags.takeClient()),
758 if (Diags.hasSourceManager())
759 setSourceManager(Diags.getSourceManager());
760 CheckOrderOfDirectives = Diags.getDiagnosticOptions().VerifyDirectives;
761 OneDiagPerDirective = Diags.getDiagnosticOptions().VerifyDirectives;
762 DisableWildcardInDiagLoc = Diags.getDiagnosticOptions().VerifyDirectives;
766 assert(!ActiveSourceFiles &&
"Incomplete parsing of source files!");
767 assert(!CurrentPreprocessor &&
"CurrentPreprocessor should be invalid!");
768 SrcManager =
nullptr;
777 if (++ActiveSourceFiles == 1) {
779 CurrentPreprocessor = PP;
780 this->LangOpts = &LangOpts;
782 const_cast<Preprocessor *
>(PP)->addCommentHandler(
this);
786 std::make_unique<VerifyFileTracker>(*
this, *SrcManager));
791 assert((!PP || CurrentPreprocessor == PP) &&
"Preprocessor changed!");
792 PrimaryClient->BeginSourceFile(LangOpts, PP);
796 assert(ActiveSourceFiles &&
"No active source files!");
797 PrimaryClient->EndSourceFile();
800 if (--ActiveSourceFiles == 0) {
801 if (CurrentPreprocessor)
803 removeCommentHandler(
this);
810 CurrentPreprocessor =
nullptr;
833 Loc = SrcManager->getExpansionLoc(Loc);
834 FileID FID = SrcManager->getFileID(Loc);
836 auto FE = SrcManager->getFileEntryRefForID(FID);
837 if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
840 HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
852 Buffer->HandleDiagnostic(DiagLevel, Info);
862 if (SrcManager && &
SM != SrcManager)
867 const char *CommentRaw =
SM.getCharacterData(CommentBegin);
868 StringRef
C(CommentRaw,
SM.getCharacterData(Comment.
getEnd()) - CommentRaw);
874 size_t loc =
C.find(
'\\');
875 if (loc == StringRef::npos) {
877 OneDiagPerDirective, DisableWildcardInDiagLoc);
882 C2.reserve(
C.size());
884 for (
size_t last = 0;; loc =
C.find(
'\\', last)) {
885 if (loc == StringRef::npos || loc ==
C.size()) {
886 C2 +=
C.substr(last);
889 C2 +=
C.substr(last, loc-last);
892 if (last <
C.size() && (
C[last] ==
'\n' ||
C[last] ==
'\r')) {
897 if (
C[last] ==
'\n' ||
C[last] ==
'\r')
898 if (
C[last] !=
C[last-1])
908 OneDiagPerDirective, DisableWildcardInDiagLoc);
925 llvm::MemoryBufferRef FromFile =
SM.getBufferOrFake(FID);
926 Lexer RawLex(FID, FromFile,
SM, LangOpts);
932 Tok.setKind(tok::comment);
935 while (
Tok.isNot(tok::eof)) {
937 if (!
Tok.is(tok::comment))
continue;
940 if (Comment.empty())
continue;
961 if (diag_begin == diag_end)
return 0;
964 llvm::raw_svector_ostream OS(Fmt);
966 if (I->first.isInvalid() || !SourceMgr)
967 OS <<
"\n (frontend)";
971 SourceMgr->getFileEntryRefForID(SourceMgr->getFileID(I->first)))
972 OS <<
" File " <<
File->getName();
973 OS <<
" Line " << SourceMgr->getPresumedLineNumber(I->first);
975 OS <<
": " << I->second;
978 const bool IsSinglePrefix =
982 << IsSinglePrefix << Prefix << Kind <<
true << OS.str();
983 return std::distance(diag_begin, diag_end);
990 std::vector<Directive *> &DL,
const char *Kind) {
994 const bool IsSinglePrefix =
998 llvm::raw_svector_ostream OS(Fmt);
999 for (
const auto *D : DL) {
1000 if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
1003 OS <<
"\n File " << SourceMgr.getFilename(D->DiagnosticLoc);
1004 if (D->MatchAnyLine)
1007 OS <<
" Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
1008 if (D->DirectiveLoc != D->DiagnosticLoc)
1009 OS <<
" (directive at "
1010 << SourceMgr.getFilename(D->DirectiveLoc) <<
':'
1011 << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) <<
')';
1012 if (!IsSinglePrefix)
1013 OS <<
" \'" << D->Spelling <<
'\'';
1014 OS <<
": " << D->Text;
1019 << IsSinglePrefix << Prefix << Kind <<
false << OS.str();
1027 DiagnosticLoc =
SM.getImmediateMacroCallerLoc(DiagnosticLoc);
1029 if (
SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
1032 const FileEntry *DiagFile =
SM.getFileEntryForID(
SM.getFileID(DiagnosticLoc));
1033 if (!DiagFile &&
SM.isWrittenInMainFile(DirectiveLoc))
1036 return (DiagFile ==
SM.getFileEntryForID(
SM.getFileID(DirectiveLoc)));
1048 llvm::raw_svector_ostream OS(Fmt);
1049 for (
const auto &[D, DiagText] : DL) {
1050 OS <<
"\n '" << D->Spelling <<
"' at line "
1051 << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) <<
" in "
1052 << SourceMgr.getFilename(D->DiagnosticLoc) <<
": " << D->Text
1053 <<
"\n does not fully match diagnostic at line "
1054 << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
1055 if (!
IsFromSameFile(SourceMgr, D->DirectiveLoc, D->DiagnosticLoc)) {
1056 OS <<
" in " << SourceMgr.getFilename(D->DiagnosticLoc);
1058 OS <<
": " << DiagText;
1062 << Kind << OS.str();
1073 bool IgnoreUnexpected) {
1074 std::vector<Directive *> LeftOnly;
1078 for (
auto &Owner : Left) {
1080 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.
DiagnosticLoc);
1082 for (
unsigned i = 0; i < D.
Max; ++i) {
1083 DiagList::iterator II, IE;
1084 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
1086 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
1087 if (LineNo1 != LineNo2)
1095 const std::string &RightText = II->second;
1099 "match when it is not needed!");
1100 IncompleteMatches.push_back({&D, II->second});
1108 if (i >= D.
Min)
break;
1109 LeftOnly.push_back(&D);
1117 unsigned num =
PrintExpected(Diags, SourceMgr, LeftOnly, Label);
1118 if (!IgnoreUnexpected)
1119 num +=
PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
1120 num +=
PrintPartial(Diags, SourceMgr, IncompleteMatches, Label);
1135 unsigned NumProblems = 0;
1178 std::vector<const Directive *> Ordered(
Unordered.size());
1180 [](
const std::unique_ptr<Directive> &D) { return &*D; });
1181 std::sort(Ordered.begin(), Ordered.end(), directiveComparator);
1184 std::vector<const Directive *> OrderedErrors = sortDirectives(ED.
Errors);
1185 std::vector<const Directive *> OrderedWarns = sortDirectives(ED.
Warnings);
1186 std::vector<const Directive *> OrderedNotes = sortDirectives(ED.
Notes);
1187 std::vector<const Directive *> OrderedRemarks = sortDirectives(ED.
Remarks);
1189 std::vector<const Directive *> OrderedDirectives = [&] {
1190 std::vector<const Directive *> OrderedEW(OrderedErrors.size() +
1191 OrderedWarns.size());
1192 std::merge(OrderedErrors.cbegin(), OrderedErrors.cend(),
1193 OrderedWarns.cbegin(), OrderedWarns.cend(), OrderedEW.begin(),
1194 directiveComparator);
1196 std::vector<const Directive *> OrderedNR(OrderedNotes.size() +
1197 OrderedRemarks.size());
1198 std::merge(OrderedNotes.cbegin(), OrderedNotes.cend(),
1199 OrderedRemarks.cbegin(), OrderedRemarks.cend(),
1200 OrderedNR.begin(), directiveComparator);
1202 std::vector<const Directive *> OrderedDirectives(OrderedEW.size() +
1204 std::merge(OrderedEW.cbegin(), OrderedEW.cend(), OrderedNR.cbegin(),
1205 OrderedNR.cend(), OrderedDirectives.begin(),
1206 directiveComparator);
1207 return OrderedDirectives;
1213 switch (DiagLevel) {
1217 "DiagIndex is out of bounds!");
1221 "DiagIndex is out of bounds!");
1225 "DiagIndex is out of bounds!");
1229 "DiagIndex is out of bounds!");
1232 llvm_unreachable(
"Unexpected diagnostic level!");
1234 llvm_unreachable(
"Unknown DiagnosticsEngine::Level enum");
1237 std::advance(It, DiagIndex);
1241 using LevelDiagPairT = std::pair<DiagnosticsEngine::Level, size_t>;
1242 static_assert(std::is_same_v<LevelDiagPairT,
1243 TextDiagnosticBuffer::AllDiagList::value_type>);
1244 int NumProblems = 0;
1246 llvm::raw_svector_ostream OS(Fmt);
1249 for (
const auto [
Directive, LevelDiagPair] : llvm::zip_equal(
1253 "Cannot compare source locations when wildcards are present");
1254 const auto [DiagLevel, DiagIndex] = LevelDiagPair;
1255 const auto &[DiagLoc, DiagText] = getLocDiagPair(DiagLevel, DiagIndex);
1259 SourceMgr.getPresumedLineNumber(DiagLoc) ==
1260 SourceMgr.getPresumedLineNumber(
Directive->DiagnosticLoc) &&
1263 if (LocsMatch && TextMatch) {
1271 OS <<
" in " << SourceMgr.getFilename(Loc);
1275 OS <<
"\n '" <<
Directive->Spelling <<
"' at line "
1276 << SourceMgr.getPresumedLineNumber(DirLoc) <<
" in "
1277 << SourceMgr.getFilename(DirLoc) <<
": " <<
Directive->Text
1278 <<
"\n matches diagnostic at line "
1279 << SourceMgr.getPresumedLineNumber(
Directive->DiagnosticLoc);
1280 printFileNameIfDifferent(DirLoc,
Directive->DiagnosticLoc);
1282 OS <<
", but diagnostic with the same message was first emitted at line "
1283 << SourceMgr.getPresumedLineNumber(DiagLoc);
1284 printFileNameIfDifferent(DirLoc, DiagLoc);
1286 OS <<
", but diagnostic at line "
1287 << SourceMgr.getPresumedLineNumber(DiagLoc);
1288 printFileNameIfDifferent(DirLoc, DiagLoc);
1289 OS <<
" was emitted first:"
1290 <<
"\n " << DiagText;
1293 if (NumProblems > 0) {
1294 Diags.
Report(diag::err_verify_directive_out_of_order) << OS.str();
1303 setSourceManager(
SM);
1313 UnparsedFiles.erase(FID);
1314 ParsedFiles.insert(std::make_pair(FID, FE ? &FE->
getFileEntry() :
nullptr));
1315 }
else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
1319 bool FoundDirectives;
1321 FoundDirectives =
false;
1326 UnparsedFiles.insert(std::make_pair(FID,
1327 UnparsedFileStatus(FE, FoundDirectives)));
1332void VerifyDiagnosticConsumer::CheckDiagnostics() {
1335 std::unique_ptr<DiagnosticConsumer> Owner = Diags.
takeClient();
1345 if (!UnparsedFiles.empty()) {
1348 for (
const auto &I : ParsedFiles)
1350 ParsedFileCache.insert(FE);
1353 for (
const auto &I : UnparsedFiles) {
1354 const UnparsedFileStatus &Status = I.second;
1358 if (FE && ParsedFileCache.count(*FE))
1362 if (Status.foundDirectives()) {
1363 llvm::report_fatal_error(
"-verify directives found after rather"
1364 " than during normal parsing of " +
1365 (FE ? FE->
getName() :
"(unknown)"));
1370 UnparsedFiles.clear();
1378 Diags.Report(diag::err_verify_no_directives).setForceEmit()
1391 if (CheckOrderOfDirectives &&
NumErrors == 0 &&
1392 State.AllDirectivesMatchExactlyOneDiag &&
1393 !State.WildcardsAreErroneouslyPresent) {
1398 ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
1401 Buffer->err_end(),
"error");
1404 Buffer->warn_end(),
"warn");
1407 Buffer->remark_end(),
"remark");
1410 Buffer->note_end(),
"note");
1413 Diags.setClient(CurClient, Owner.release() !=
nullptr);
1416 Buffer.reset(
new TextDiagnosticBuffer());
1420std::unique_ptr<Directive>
1426 return std::make_unique<StandardDirective>(
1431 std::string RegexStr;
1433 while (!S.empty()) {
1434 if (S.consume_front(
"{{")) {
1435 size_t RegexMatchLength = S.find(
"}}");
1436 assert(RegexMatchLength != StringRef::npos);
1439 RegexStr.append(S.data(), RegexMatchLength);
1441 S = S.drop_front(RegexMatchLength + 2);
1443 size_t VerbatimMatchLength = S.find(
"{{");
1444 if (VerbatimMatchLength == StringRef::npos)
1445 VerbatimMatchLength = S.size();
1447 RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
1448 S = S.drop_front(VerbatimMatchLength);
1452 return std::make_unique<RegexDirective>(
Defines the Diagnostic-related interfaces.
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
VerifyDiagnosticConsumer::ExpectedData ExpectedData
static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc)
Determine whether two source locations come from the same file.
static unsigned PrintPartial(DiagnosticsEngine &Diags, SourceManager &SourceMgr, llvm::SmallVector< std::pair< Directive *, std::string > > &DL, const char *Kind)
Takes a list of diagnostics that were partially matched and prints them.
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 unsigned CheckResultsAreInOrder(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, const ExpectedData &ED)
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::ParsingState &State, VerifyDiagnosticConsumer::MarkerTracker &Markers, bool OneDiagPerDirective, bool DisableWildcardInDiagLoc)
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...
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.
bool isIncrementalProcessingEnabled() const
Returns true if incremental processing is enabled.
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 <foo> 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
AllDiagList::const_iterator all_begin() const
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
AllDiagList::const_iterator all_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
virtual DiagnosticMatchResult match(StringRef S) const =0
static const unsigned MaxCount
Constant representing n or more matches.
const std::string Spelling
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, StringRef Spelling, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max, bool FullMatchRequired)
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.
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...
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',...
@ AtLeastPartial
Match, but not a full match.
@ Full
Match, but we didn't check for full match.
ExpectedData - owns directive objects and deletes on destructor.