summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Support/FileCheck.h2
-rw-r--r--llvm/lib/Support/FileCheck.cpp19
-rw-r--r--llvm/test/FileCheck/dump-input-annotations.txt78
-rw-r--r--llvm/test/FileCheck/dump-input-enable.txt2
-rw-r--r--llvm/utils/FileCheck/FileCheck.cpp83
5 files changed, 138 insertions, 46 deletions
diff --git a/llvm/include/llvm/Support/FileCheck.h b/llvm/include/llvm/Support/FileCheck.h
index b1c6689e711..54820bec1cb 100644
--- a/llvm/include/llvm/Support/FileCheck.h
+++ b/llvm/include/llvm/Support/FileCheck.h
@@ -163,6 +163,8 @@ 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.
+ MatchFinalAndExpected,
/// Indicates the final match for an excluded pattern.
MatchFinalButExcluded,
/// Indicates the final match for an expected pattern, but the match is on
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index a2f5db1e2c1..068fa96b9fa 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -416,14 +416,19 @@ static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
const SourceMgr &SM, SMLoc Loc,
Check::FileCheckType CheckTy,
StringRef Buffer, size_t Pos, size_t Len,
- std::vector<FileCheckDiag> *Diags) {
+ std::vector<FileCheckDiag> *Diags,
+ bool AdjustPrevDiag = false) {
SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
SMRange Range(Start, End);
// TODO: The second condition will disappear when we extend this to handle
// more match types.
- if (Diags && MatchTy != FileCheckDiag::MatchTypeCount)
- Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
+ if (Diags && MatchTy != FileCheckDiag::MatchTypeCount) {
+ if (AdjustPrevDiag)
+ Diags->rbegin()->MatchTy = MatchTy;
+ else
+ Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
+ }
return Range;
}
@@ -905,7 +910,7 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
return;
}
SMRange MatchRange = ProcessMatchResult(
- ExpectedMatch ? FileCheckDiag::MatchTypeCount
+ ExpectedMatch ? FileCheckDiag::MatchFinalAndExpected
: FileCheckDiag::MatchFinalButExcluded,
SM, Loc, Pat.getCheckTy(), Buffer, MatchPos, MatchLen, Diags);
std::string Message = formatv("{0}: {1} string found in input",
@@ -1060,7 +1065,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
if (CheckNext(SM, SkippedRegion)) {
ProcessMatchResult(FileCheckDiag::MatchFinalButWrongLine, SM, Loc,
Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
- Diags);
+ Diags, Req.Verbose);
return StringRef::npos;
}
@@ -1069,7 +1074,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
if (CheckSame(SM, SkippedRegion)) {
ProcessMatchResult(FileCheckDiag::MatchFinalButWrongLine, SM, Loc,
Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
- Diags);
+ Diags, Req.Verbose);
return StringRef::npos;
}
@@ -1278,6 +1283,8 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
SM.PrintMessage(OldStart, SourceMgr::DK_Note,
"match discarded, overlaps earlier DAG match here",
{OldRange});
+ if (Diags)
+ Diags->pop_back();
}
MatchPos = MI->End;
}
diff --git a/llvm/test/FileCheck/dump-input-annotations.txt b/llvm/test/FileCheck/dump-input-annotations.txt
index c808fb2c6d4..4dc32418e1f 100644
--- a/llvm/test/FileCheck/dump-input-annotations.txt
+++ b/llvm/test/FileCheck/dump-input-annotations.txt
@@ -21,6 +21,7 @@
; ALIGN:Full input was:
; ALIGN-NEXT:<<<<<<
; ALIGN-NEXT: 1: hello world
+; ALIGN-NEXT:check:1 ^~~~~
; ALIGN-NEXT:check:2'0 X~~~~
; ALIGN-NEXT: 2: goodbye
; ALIGN-NEXT:check:2'0 ~~~~~~~
@@ -54,6 +55,7 @@
; CHK: <<<<<<
; CHK-NEXT: 1: hello
+; CHK-V-NEXT: check:1 ^~~~~
; CHK-NEXT: 2: again
; CHK-NEXT: check:2'0 X~~~~
; CHK-NEXT: 3: whirled
@@ -75,19 +77,22 @@
; RUN: echo 'CHECK-COUNT-3: pete' > %t.chk
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefix=CNT
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-Q
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=CNT,CNT-V
-; CNT: <<<<<<
-; CNT-NEXT: 1: pete
-; CNT-NEXT: 2: repete
-; CNT-NEXT: 3: repeat
-; CNT-NEXT: count:1 X~~~~~ error: no match found
-; CNT-NEXT: >>>>>>
-; CNT-NOT: {{.}}
+; CNT: <<<<<<
+; CNT-NEXT: 1: pete
+; CNT-V-NEXT: count:1'0 ^~~~
+; CNT-NEXT: 2: repete
+; CNT-V-NEXT: count:1'1 ^~~~
+; CNT-NEXT: 3: repeat
+; CNT-Q-NEXT: count:1 X~~~~~ error: no match found
+; CNT-V-NEXT: count:1'2 X~~~~~ error: no match found
+; CNT-NEXT: >>>>>>
+; CNT-NOT: {{.}}
;--------------------------------------------------
; CHECK-NEXT (also: EOF search-range, wrong-line match)
@@ -110,10 +115,12 @@
; RUN: | FileCheck -match-full-lines %s -check-prefixes=NXT,NXT-V,NXT-VV
; NXT: <<<<<<
-; NXT-NEXT: 1: hello
-; NXT-NEXT: 2: again
-; NXT-NEXT: 3:
-; NXT-NEXT: next:3 X error: no match found
+; NXT-NEXT: 1: hello
+; NXT-V-NEXT: check:1 ^~~~~
+; NXT-NEXT: 2: again
+; NXT-V-NEXT: next:2 ^~~~~
+; NXT-NEXT: 3:
+; NXT-NEXT: next:3 X error: no match found
; NXT-NEXT: >>>>>>
; NXT-NOT: {{.}}
@@ -135,7 +142,8 @@
; NXT2-NOT: {{.}}
;--------------------------------------------------
-; CHECK-SAME (also: single-char search range, wrong-line match)
+; CHECK-SAME (also: multiple annotations per line, single-char search range,
+; wrong-line match)
;--------------------------------------------------
; Good match and no match.
@@ -154,8 +162,10 @@
; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM,SAM-V,SAM-VV
; SAM: <<<<<<
-; SAM-NEXT: 1: hello world!
-; SAM-NEXT: same:3 X error: no match found
+; SAM-NEXT: 1: hello world!
+; SAM-V-NEXT: check:1 ^~~~~
+; SAM-V-NEXT: same:2 ^~~~~
+; SAM-NEXT: same:3 X error: no match found
; SAM-NEXT: >>>>>>
; SAM-NOT: {{.}}
@@ -168,13 +178,16 @@
; SAM2: <<<<<<
; SAM2-NEXT: 1: hello world!
+; SAM2-NEXT: check:1 ^~~~~
+; SAM2-NEXT: same:2 ^~~~~
; 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, wrong-line match)
+; CHECK-EMPTY (also: search range ends at label, single-char match, wrong-line
+; match)
;--------------------------------------------------
; Good match and no match.
@@ -203,11 +216,14 @@
; EMP: <<<<<<
; EMP-NEXT: 1: hello
+; EMP-V-NEXT: check:1 ^~~~~
; EMP-NEXT: 2:
+; EMP-V-NEXT: empty:2 ^
; EMP-NEXT: 3: world
; EMP-NEXT: empty:3 X~~~~
; EMP-NEXT: 4: label
; EMP-NEXT: empty:3 ~~~~~ error: no match found
+; EMP-V-NEXT: label:4 ^~~~~
; EMP-NEXT: >>>>>>
; EMP-NOT: {{.}}
@@ -228,6 +244,7 @@
; EMP2: <<<<<<
; EMP2-NEXT: 1: hello
+; EMP2-V-NEXT: check:1 ^~~~~
; EMP2-NEXT: 2: world
; EMP2-NEXT: 3:
; EMP2-NEXT: empty:2 ! error: match on wrong line
@@ -235,7 +252,7 @@
; EMP2-NOT: {{.}}
;--------------------------------------------------
-; CHECK-NOT
+; CHECK-NOT (also: EOF pattern)
;--------------------------------------------------
; No match (success) and unexpected match (error).
@@ -259,6 +276,8 @@
; NOT-NEXT: 2: world
; NOT-NEXT: not:2 !~~~~ error: no match expected
; NOT-NEXT: 3: again
+; NOT-VV-NEXT: 4:
+; NOT-VV-NEXT: eof:2 ^
; NOT-NEXT: >>>>>>
; NOT-NOT: {{.}}
@@ -278,11 +297,12 @@
; NOT2-NEXT: 2: world
; NOT2-NEXT: not:2 !~~~~ error: no match expected
; NOT2-NEXT: 3: again
+; NOT2-V-NEXT: check:3 ^~~
; NOT2-NEXT: >>>>>>
; NOT2-NOT: {{.}}
;--------------------------------------------------
-; CHECK-DAG
+; CHECK-DAG (also: matches in different order than directives)
;--------------------------------------------------
; Good match, discarded match plus good match, and no match.
@@ -297,22 +317,28 @@
; RUN: echo 'CHECK-DAG: def' >> %t.chk
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-Q
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-V
; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv 2>&1 \
-; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
+; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG,DAG-V,DAG-VV
; DAG: <<<<<<
-; DAG-NEXT: 1: abc
-; DAG-NEXT: 2: def
-; DAG-NEXT: 3: abc
-; DAG-NEXT: dag:4 X~~ error: no match found
+; DAG-NEXT: 1: abc
+; DAG-V-NEXT: dag:2 ^~~
+; DAG-NEXT: 2: def
+; DAG-V-NEXT: dag:1 ^~~
+; DAG-NEXT: 3: abc
+; DAG-V-NEXT: dag:3 ^~~
+; DAG-NEXT: dag:4 X~~ error: no match found
; DAG-NEXT: >>>>>>
; DAG-NOT: {{.}}
;--------------------------------------------------
; CHECK-LABEL
+;
+; FIXME: Labels sometimes produce redundant diagnostics for good matches.
+; That bug is independent of but affects -dump-input.
;--------------------------------------------------
; Good match and no match.
@@ -335,6 +361,8 @@
; LAB: <<<<<<
; LAB-NEXT: 1: lab0
+; LAB-V-NEXT: label:1'0 ^~~~
+; LAB-V-NEXT: label:1'1 ^~~~
; LAB-NEXT: 2: foo
; LAB-NEXT: label:3'0 X~~
; LAB-NEXT: 3: lab1
diff --git a/llvm/test/FileCheck/dump-input-enable.txt b/llvm/test/FileCheck/dump-input-enable.txt
index cbc167ac079..21893979aca 100644
--- a/llvm/test/FileCheck/dump-input-enable.txt
+++ b/llvm/test/FileCheck/dump-input-enable.txt
@@ -112,7 +112,9 @@ HELP-NOT: {{.}}
; CHECK-GOOD: Full input was:
; CHECK-GOOD-NEXT: <<<<<<
; CHECK-GOOD-NEXT: 1: ciao
+; CHECK-GOOD-NEXT: check:1 ^~~~
; CHECK-GOOD-NEXT: 2: world
+; CHECK-GOOD-NEXT: next:2 ^~~~~
; CHECK-GOOD-NEXT: >>>>>>
; CHECK-ERR: Full input was:
diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp
index 1f6caeee2e1..6248453a754 100644
--- a/llvm/utils/FileCheck/FileCheck.cpp
+++ b/llvm/utils/FileCheck/FileCheck.cpp
@@ -137,12 +137,15 @@ struct MarkerStyle {
/// A note to follow the marker, or empty string if none.
std::string Note;
MarkerStyle() {}
- MarkerStyle(char Lead, raw_ostream::Colors Color, const std::string &Note)
+ MarkerStyle(char Lead, raw_ostream::Colors Color,
+ const std::string &Note = "")
: Lead(Lead), Color(Color), Note(Note) {}
};
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
switch (MatchTy) {
+ case FileCheckDiag::MatchFinalAndExpected:
+ return MarkerStyle('^', raw_ostream::GREEN);
case FileCheckDiag::MatchFinalButExcluded:
return MarkerStyle('!', raw_ostream::RED, "error: no match expected");
case FileCheckDiag::MatchFinalButWrongLine:
@@ -181,6 +184,9 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
// Markers on annotation lines.
OS << " - ";
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
+ OS << " marks good match (reported if -v)\n"
+ << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
OS << " marks bad match, such as:\n"
<< " - CHECK-NEXT on same line as previous match (error)\n"
@@ -195,9 +201,13 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
// Colors.
OS << " - colors ";
+ WithColor(OS, raw_ostream::GREEN, true) << "success";
+ OS << ", ";
WithColor(OS, raw_ostream::RED, true) << "error";
OS << ", ";
WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
+ OS << ", ";
+ WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
OS << "\n\n"
<< "If you are not seeing color above or in input dumps, try: -color\n";
}
@@ -222,6 +232,8 @@ struct InputAnnotation {
unsigned InputStartCol, InputEndCol;
/// The marker to use.
MarkerStyle Marker;
+ /// Whether this annotation represents a final match for an expected pattern.
+ bool FinalAndExpectedMatch;
};
/// Get an abbreviation for the check type.
@@ -289,6 +301,8 @@ static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
MarkerStyle Marker = GetMarker(DiagItr->MatchTy);
A.Marker = Marker;
+ A.FinalAndExpectedMatch =
+ DiagItr->MatchTy == FileCheckDiag::MatchFinalAndExpected;
// Compute the mark location, and break annotation into multiple
// annotations if it spans multiple lines.
@@ -328,15 +342,17 @@ static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
B.Marker.Note = "";
} else
B.InputEndCol = DiagItr->InputEndCol;
+ B.FinalAndExpectedMatch = A.FinalAndExpectedMatch;
Annotations.push_back(B);
}
}
}
}
-static void DumpAnnotatedInput(
- raw_ostream &OS, StringRef InputFileText,
- std::vector<InputAnnotation> &Annotations, unsigned LabelWidth) {
+static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
+ StringRef InputFileText,
+ std::vector<InputAnnotation> &Annotations,
+ unsigned LabelWidth) {
OS << "Full input was:\n<<<<<<\n";
// Sort annotations.
@@ -359,9 +375,15 @@ static void DumpAnnotatedInput(
return A.InputLine < B.InputLine;
if (A.CheckLine != B.CheckLine)
return A.CheckLine < B.CheckLine;
- assert(A.CheckDiagIndex != B.CheckDiagIndex &&
- "expected diagnostic indices to be unique within a "
- " check line");
+ // FIXME: Sometimes CHECK-LABEL reports its match twice with
+ // other diagnostics in between, and then diag index incrementing
+ // fails to work properly, and then this assert fails. We should
+ // suppress one of those diagnostics or do a better job of
+ // computing this index. For now, we just produce a redundant
+ // CHECK-LABEL annotation.
+ // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
+ // "expected diagnostic indices to be unique within a "
+ // " check line");
return A.CheckDiagIndex < B.CheckDiagIndex;
});
@@ -393,14 +415,45 @@ static void DumpAnnotatedInput(
WithColor(OS, raw_ostream::BLACK, true)
<< format_decimal(Line, LabelWidth) << ": ";
- // Print numbered line.
+ // For case where -v and colors are enabled, find the annotations for final
+ // matches for expected patterns in order to highlight everything else in
+ // the line. There are no such annotations if -v is disabled.
+ std::vector<InputAnnotation> FinalAndExpectedMatches;
+ if (Req.Verbose && WithColor(OS).colorsEnabled()) {
+ for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
+ ++I) {
+ if (I->FinalAndExpectedMatch)
+ FinalAndExpectedMatches.push_back(*I);
+ }
+ }
+
+ // Print numbered line with highlighting where there are no matches for
+ // expected patterns.
bool Newline = false;
- while (InputFilePtr != InputFileEnd && !Newline) {
- if (*InputFilePtr == '\n')
- Newline = true;
- else
- OS << *InputFilePtr;
- ++InputFilePtr;
+ {
+ WithColor COS(OS);
+ bool InMatch = false;
+ if (Req.Verbose)
+ COS.changeColor(raw_ostream::CYAN, true, true);
+ for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
+ bool WasInMatch = InMatch;
+ InMatch = false;
+ for (auto M : FinalAndExpectedMatches) {
+ if (M.InputStartCol <= Col && Col < M.InputEndCol) {
+ InMatch = true;
+ break;
+ }
+ }
+ if (!WasInMatch && InMatch)
+ COS.resetColor();
+ else if (WasInMatch && !InMatch)
+ COS.changeColor(raw_ostream::CYAN, true, true);
+ if (*InputFilePtr == '\n')
+ Newline = true;
+ else
+ COS << *InputFilePtr;
+ ++InputFilePtr;
+ }
}
OS << '\n';
unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
@@ -561,7 +614,7 @@ int main(int argc, char **argv) {
std::vector<InputAnnotation> Annotations;
unsigned LabelWidth;
BuildInputAnnotations(Diags, Annotations, LabelWidth);
- DumpAnnotatedInput(errs(), InputFileText, Annotations, LabelWidth);
+ DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
}
return ExitCode;
OpenPOWER on IntegriCloud