diff --git a/include/llvm/Support/FileCheck.h b/include/llvm/Support/FileCheck.h index ace90cec8fb..8c0777731ac 100644 --- a/include/llvm/Support/FileCheck.h +++ b/include/llvm/Support/FileCheck.h @@ -163,6 +163,9 @@ struct FileCheckDiag { /// example, there might be a fuzzy match after a fail. enum MatchType { // TODO: More members will appear with later patches in this series. + /// Indicates the final match for an expected pattern, but the match is on + /// the wrong line. + MatchFinalButWrongLine, /// Indicates no match for an expected pattern. MatchNoneButExpected, /// Indicates a possible intended match because there's no perfect match. diff --git a/lib/Support/FileCheck.cpp b/lib/Support/FileCheck.cpp index 49e2500a63a..817e8d95bf0 100644 --- a/lib/Support/FileCheck.cpp +++ b/lib/Support/FileCheck.cpp @@ -1047,17 +1047,27 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT // or CHECK-NOT if (!IsLabelScanMode) { - StringRef SkippedRegion = Buffer.substr(LastPos, FirstMatchPos - LastPos); + size_t MatchPos = FirstMatchPos - LastPos; + StringRef MatchBuffer = Buffer.substr(LastPos); + StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). - if (CheckNext(SM, SkippedRegion)) + if (CheckNext(SM, SkippedRegion)) { + ProcessMatchResult(FileCheckDiag::MatchFinalButWrongLine, SM, Loc, + Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, + Diags); return StringRef::npos; + } // If this check is a "CHECK-SAME", verify that the previous match was on // the same line (i.e. that there is no newline between them). - if (CheckSame(SM, SkippedRegion)) + if (CheckSame(SM, SkippedRegion)) { + ProcessMatchResult(FileCheckDiag::MatchFinalButWrongLine, SM, Loc, + Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen, + Diags); return StringRef::npos; + } // If this match had "not strings", verify that they don't exist in the // skipped region. diff --git a/test/FileCheck/dump-input-annotations.txt b/test/FileCheck/dump-input-annotations.txt index 94c35e2c9f6..d225ed2bd14 100644 --- a/test/FileCheck/dump-input-annotations.txt +++ b/test/FileCheck/dump-input-annotations.txt @@ -90,7 +90,7 @@ ; CNT-NOT: {{.}} ;-------------------------------------------------- -; CHECK-NEXT (also: EOF search-range) +; CHECK-NEXT (also: EOF search-range, wrong-line match) ;-------------------------------------------------- ; Good match and no match. @@ -117,8 +117,25 @@ ; NXT-NEXT: >>>>>> ; NXT-NOT: {{.}} +; Wrong-line match. + +; RUN: echo 'yonder' >> %t.in +; RUN: echo 'world' >> %t.in + +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \ +; RUN: | FileCheck -match-full-lines %s -check-prefix=NXT2 + +; NXT2: <<<<<< +; NXT2-NEXT: 1: hello +; NXT2-NEXT: 2: again +; NXT2-NEXT: 3: yonder +; NXT2-NEXT: 4: world +; NXT2-NEXT: next:3 !~~~~ error: match on wrong line +; NXT2-NEXT: >>>>>> +; NXT2-NOT: {{.}} + ;-------------------------------------------------- -; CHECK-SAME (also: single-char search range) +; CHECK-SAME (also: single-char search range, wrong-line match) ;-------------------------------------------------- ; Good match and no match. @@ -142,8 +159,22 @@ ; SAM-NEXT: >>>>>> ; SAM-NOT: {{.}} +; Wrong-line match. + +; RUN: echo 'again' >> %t.in + +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \ +; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM2 + +; SAM2: <<<<<< +; SAM2-NEXT: 1: hello world! +; SAM2-NEXT: 2: again +; SAM2-NEXT: same:3 !~~~~ error: match on wrong line +; SAM2-NEXT: >>>>>> +; SAM2-NOT: {{.}} + ;-------------------------------------------------- -; CHECK-EMPTY (also: search range ends at label) +; CHECK-EMPTY (also: search range ends at label, wrong-line match) ;-------------------------------------------------- ; Good match and no match. @@ -180,6 +211,29 @@ ; EMP-NEXT: >>>>>> ; EMP-NOT: {{.}} +; Wrong-line match. + +; RUN: echo 'hello' > %t.in +; RUN: echo 'world' >> %t.in + +; RUN: echo 'CHECK: hello' > %t.chk +; RUN: echo 'CHECK-EMPTY:' >> %t.chk + +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \ +; RUN: | FileCheck -match-full-lines %s -check-prefix=EMP2 +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \ +; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP2,EMP2-V +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \ +; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP2,EMP2-V,EMP2-VV + +; EMP2: <<<<<< +; EMP2-NEXT: 1: hello +; EMP2-NEXT: 2: world +; EMP2-NEXT: 3: +; EMP2-NEXT: empty:2 ! error: match on wrong line +; EMP2-NEXT: >>>>>> +; EMP2-NOT: {{.}} + ;-------------------------------------------------- ; CHECK-DAG ;-------------------------------------------------- diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index c6846f7da71..d027f3e6676 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -143,6 +143,8 @@ struct MarkerStyle { static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) { switch (MatchTy) { + case FileCheckDiag::MatchFinalButWrongLine: + return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line"); case FileCheckDiag::MatchNoneButExpected: return MarkerStyle('X', raw_ostream::RED, "error: no match found"); case FileCheckDiag::MatchFuzzy: @@ -177,8 +179,13 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) { // Markers on annotation lines. OS << " - "; + WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~"; + OS << " marks bad match, such as:\n" + << " - CHECK-NEXT on same line as previous match (error)\n" + << " - "; WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~"; - OS << " marks search range when no match is found\n" + OS << " marks search range when no match is found, such as:\n" + << " - CHECK-NEXT not found (error)\n" << " - "; WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?"; OS << " marks fuzzy match when no match is found\n";