diff --git a/llvm/test/FileCheck/dump-input-filter.txt b/llvm/test/FileCheck/dump-input-filter.txt --- a/llvm/test/FileCheck/dump-input-filter.txt +++ b/llvm/test/FileCheck/dump-input-filter.txt @@ -115,6 +115,102 @@ ; ALL-NEXT: check:3'0 ~~~ ; ALL-NEXT: >>>>>> +; ANNOTATION-FULL: <<<<<< +; ANNOTATION-FULL-NEXT: 1: start +; ANNOTATION-FULL-NEXT: check:1 ^~~~~ +; ANNOTATION-FULL-NEXT: 2: foo0 +; ANNOTATION-FULL-NEXT: 3: foo1 +; ANNOTATION-FULL-NEXT: . +; ANNOTATION-FULL-NEXT: . +; ANNOTATION-FULL-NEXT: . +; ANNOTATION-FULL-NEXT: 10: foo8 +; ANNOTATION-FULL-NEXT: 11: foo9 +; ANNOTATION-FULL-NEXT: 12: hello +; ANNOTATION-FULL-NEXT: check:2 ^~~~~ +; ANNOTATION-FULL-NEXT: 13: foo0 +; ANNOTATION-FULL-NEXT: check:3'0 X~~~ error: no match found +; ANNOTATION-FULL-NEXT: 14: foo1 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 15: foo2 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 16: foo3 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 17: foo4 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 18: foo5 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 19: foo6 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 20: foo7 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 21: foo8 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 22: foo9 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 23: word +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: check:3'1 ? possible intended match +; ANNOTATION-FULL-NEXT: 24: foo0 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 25: foo1 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 26: foo2 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 27: foo3 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 28: foo4 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 29: foo5 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 30: foo6 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 31: foo7 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 32: foo8 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 33: foo9 +; ANNOTATION-FULL-NEXT: check:3'0 ~~~~ +; ANNOTATION-FULL-NEXT: 34: end +; ANNOTATION-FULL-NEXT: check:3'0 ~~~ +; ANNOTATION-FULL-NEXT: >>>>>> + +; ANNOTATION: <<<<<< +; ANNOTATION-NEXT: 1: start +; ANNOTATION-NEXT: check:1 ^~~~~ +; ANNOTATION-NEXT: 2: foo0 +; ANNOTATION-NEXT: 3: foo1 +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: 10: foo8 +; ANNOTATION-NEXT: 11: foo9 +; ANNOTATION-NEXT: 12: hello +; ANNOTATION-NEXT: check:2 ^~~~~ +; ANNOTATION-NEXT: 13: foo0 +; ANNOTATION-NEXT: check:3'0 X~~~ error: no match found +; ANNOTATION-NEXT: 14: foo1 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: 15: foo2 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: 21: foo8 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: 22: foo9 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: 23: word +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: check:3'1 ? possible intended match +; ANNOTATION-NEXT: 24: foo0 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: 25: foo1 +; ANNOTATION-NEXT: check:3'0 ~~~~ +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: . +; ANNOTATION-NEXT: >>>>>> + ; ERROR: <<<<<< ; ERROR-NEXT: . ; ERROR-NEXT: . @@ -148,28 +244,149 @@ ; ERROR-NEXT: >>>>>> ;-------------------------------------------------- -; Check how -dump-input affects filter. +; Check -dump-input-filter=. +;-------------------------------------------------- + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=foobar \ +; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL + +BADVAL: {{F|f}}ile{{C|c}}heck{{.*}}: for the --dump-input-filter option: Cannot find option named 'foobar'! + +;-------------------------------------------------- +; Check -dump-input-filter explicit values. +;-------------------------------------------------- + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=all \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=annotation-full \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION-FULL + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=annotation \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION + +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=error \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR + +;-------------------------------------------------- +; Check -dump-input-filter defaults. ;-------------------------------------------------- -; no -dump-input => include errors. +; no -dump-input => -dump-input-filter=error ; RUN: %ProtectFileCheckOutput \ ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ ; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR -; -dump-input=fail => include errors. +; -dump-input=fail => -dump-input-filter=error ; RUN: %ProtectFileCheckOutput \ ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ ; RUN: -dump-input=fail \ ; RUN: | FileCheck %s -match-full-lines -check-prefixes=ERROR -; -dump-input=always => include all. +; -dump-input=always => -dump-input-filter=all ; RUN: %ProtectFileCheckOutput \ ; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ ; RUN: -dump-input=always \ ; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL ;-------------------------------------------------- -; Check that other kinds of errors are included by -dump-input=fail. +; Check multiple -dump-input-filter options. +; +; This might occur when a test author specifies -dump-input-filter on a specific +; FileCheck call while a test runner specifies -dump-input-filter in +; FILECHECK_OPTS, but check the behavior generally. +; +; The value providing the most information wins. +;-------------------------------------------------- + +;- - - - - - - - - - - - - - - - - - - - - - - - - +; Check duplicate. +;- - - - - - - - - - - - - - - - - - - - - - - - - + +; all, all => all +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=all -dump-input-filter=all \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL + +;- - - - - - - - - - - - - - - - - - - - - - - - - +; Check precedence. +;- - - - - - - - - - - - - - - - - - - - - - - - - + +; all, annotation-full => all +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=all -dump-input-filter=annotation-full \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ALL + +; annotation-full, annotation => annotation-full +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=annotation-full \ +; RUN: -dump-input-filter=annotation \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION-FULL + +; annotation, error => annotation +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=annotation -dump-input-filter=error \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION + +;- - - - - - - - - - - - - - - - - - - - - - - - - +; Check that order doesn't matter. +;- - - - - - - - - - - - - - - - - - - - - - - - - + +; error, annotation => annotation +; RUN: %ProtectFileCheckOutput \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=error -dump-input-filter=annotation \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION + +;- - - - - - - - - - - - - - - - - - - - - - - - - +; Check that FILECHECK_OPTS isn't handled differently. +;- - - - - - - - - - - - - - - - - - - - - - - - - + +; annotation, error => annotation +; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-filter=annotation \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=error \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION + +; error, annotation => annotation +; RUN: %ProtectFileCheckOutput FILECHECK_OPTS=-dump-input-filter=error \ +; RUN: not FileCheck -dump-input-context=2 -vv %t.chk < %t.in 2>&1 \ +; RUN: -dump-input-filter=annotation \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=ANNOTATION + +;-------------------------------------------------- +; Check the case where all input lines are filtered out. +;-------------------------------------------------- + +; RUN: echo 'CHECK: hello' > %t.good.chk + +; RUN: %ProtectFileCheckOutput \ +; RUN: FileCheck -dump-input=always -dump-input-filter=error -vv %t.good.chk \ +; RUN: < %t.in 2>&1 \ +; RUN: | FileCheck %s -match-full-lines -check-prefixes=EMPTY + +; EMPTY: <<<<<< +; EMPTY-NEXT: . +; EMPTY-NEXT: . +; EMPTY-NEXT: . +; EMPTY-NEXT: >>>>>> + +;-------------------------------------------------- +; Check that other kinds of errors are included by -dump-input-filter=error. ; ; "error: no match found" and "possible intended match" are checked above. ;-------------------------------------------------- @@ -182,7 +399,7 @@ ; RUN: echo 'CHECK-NOT: foo' > %t.not-err.chk ; RUN: %ProtectFileCheckOutput \ -; RUN: not FileCheck -dump-input-context=0 -dump-input=fail \ +; RUN: not FileCheck -dump-input-context=0 -dump-input-filter=error \ ; RUN: %t.not-err.chk < %t.not-err.in 2>&1 \ ; RUN: | FileCheck %s -match-full-lines -check-prefixes=NOT-ERR @@ -200,9 +417,9 @@ ; RUN: echo 'CHECK-NEXT: bar' >> %t.next-err.chk ; RUN: %ProtectFileCheckOutput \ -; RUN: not FileCheck -dump-input-context=0 -dump-input=fail \ +; RUN: not FileCheck -dump-input-context=0 -dump-input-filter=error \ ; RUN: %t.next-err.chk < %t.next-err.in 2>&1 \ ; RUN: | FileCheck %s -match-full-lines -check-prefixes=NEXT-ERR ; NEXT-ERR: 3: bar -; NEXT-ERR-NEXT: next:2 !~~ error: match on wrong line +; NEXT-ERR-NEXT: next:2 !~~ error: match on wrong line \ No newline at end of file diff --git a/llvm/utils/FileCheck/FileCheck.cpp b/llvm/utils/FileCheck/FileCheck.cpp --- a/llvm/utils/FileCheck/FileCheck.cpp +++ b/llvm/utils/FileCheck/FileCheck.cpp @@ -128,11 +128,38 @@ clEnumValN(DumpInputFail, "fail", "Dump input on failure"), clEnumValN(DumpInputNever, "never", "Never dump input"))); +// The order of DumpInputFilterValue members affects their precedence, as +// documented for -dump-input-filter below. +enum DumpInputFilterValue { + DumpInputFilterError, + DumpInputFilterAnnotation, + DumpInputFilterAnnotationFull, + DumpInputFilterAll +}; + +static cl::list DumpInputFilters( + "dump-input-filter", + cl::desc("In the dump requested by -dump-input, print only input lines of\n" + "kind plus any context specified by -dump-input-context.\n" + "When there are multiple occurrences of this option, the \n" + "that appears earliest in the list below has precedence. The\n" + "default is 'error' when -dump-input=fail, and it's 'all' when\n" + "-dump-input=always.\n"), + cl::value_desc("kind"), + cl::values(clEnumValN(DumpInputFilterAll, "all", "All input lines"), + clEnumValN(DumpInputFilterAnnotationFull, "annotation-full", + "Input lines with annotations"), + clEnumValN(DumpInputFilterAnnotation, "annotation", + "Input lines with starting points of annotations"), + clEnumValN(DumpInputFilterError, "error", + "Input lines with starting points of error " + "annotations"))); + static cl::list DumpInputContexts( "dump-input-context", cl::value_desc("N"), - cl::desc("In the dump requested by -dump-input=fail, print input\n" - "lines before and input lines after the starting line of\n" - "any error diagnostic. When there are multiple occurrences of\n" + cl::desc("In the dump requested by -dump-input, print input lines\n" + "before and input lines after any lines specified by\n" + "-dump-input-filter. When there are multiple occurrences of\n" "this option, the largest specified has precedence. The\n" "default is 5.\n")); @@ -158,8 +185,7 @@ raw_ostream::Colors Color; /// A note to follow the marker, or empty string if none. std::string Note; - /// Does this marker indicate inclusion by the input filter implied by - /// -dump-input=fail? + /// Does this marker indicate inclusion by -dump-input-filter=error? bool FiltersAsError; MarkerStyle() {} MarkerStyle(char Lead, raw_ostream::Colors Color, @@ -201,7 +227,8 @@ << "\n" << "Related command-line options:\n" << " - -dump-input= enables or disables the input dump\n" - << " - -dump-input-context= adjusts the context of errors\n" + << " - -dump-input-filter= filters the input lines\n" + << " - -dump-input-context= adjusts the context of filtered lines\n" << " - -v and -vv add more annotations\n" << " - -color forces colors to be enabled both in the dump and below\n" << " - -help documents the above options in more detail\n" @@ -251,7 +278,7 @@ OS << " - "; WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "..."; OS << " indicates elided input lines and annotations, as specified by\n" - << " -dump-input=fail and -dump-input-context\n"; + << " -dump-input-filter and -dump-input-context\n"; // Colors. OS << " - colors "; @@ -416,15 +443,28 @@ } static unsigned FindInputLineInFilter( - bool FilterOnError, unsigned CurInputLine, + DumpInputFilterValue DumpInputFilter, unsigned CurInputLine, const std::vector::iterator &AnnotationBeg, const std::vector::iterator &AnnotationEnd) { - if (!FilterOnError) + if (DumpInputFilter == DumpInputFilterAll) return CurInputLine; for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd; ++AnnotationItr) { - if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError) + switch (DumpInputFilter) { + case DumpInputFilterAll: + llvm_unreachable("unexpected DumpInputFilterAll"); + break; + case DumpInputFilterAnnotationFull: return AnnotationItr->InputLine; + case DumpInputFilterAnnotation: + if (AnnotationItr->IsFirstLine) + return AnnotationItr->InputLine; + break; + case DumpInputFilterError: + if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError) + return AnnotationItr->InputLine; + break; + } } return UINT_MAX; } @@ -449,7 +489,7 @@ } static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req, - bool DumpInputFilterOnError, + DumpInputFilterValue DumpInputFilter, unsigned DumpInputContext, StringRef InputFileText, std::vector &Annotations, @@ -540,7 +580,7 @@ // Compute the previous and next line included by the filter. if (NextLineInFilter < Line) - NextLineInFilter = FindInputLineInFilter(DumpInputFilterOnError, Line, + NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line, AnnotationItr, AnnotationEnd); assert(NextLineInFilter && "expected NextLineInFilter to be computed"); if (NextLineInFilter == Line) @@ -548,7 +588,7 @@ // Elide this input line and its annotations if it's not within the // context specified by -dump-input-context of an input line included by - // the dump filter. However, in case the resulting ellipsis would occupy + // -dump-input-filter. However, in case the resulting ellipsis would occupy // more lines than the input lines and annotations it elides, buffer the // elided lines and annotations so we can print them instead. raw_ostream *LineOS = &OS; @@ -661,7 +701,13 @@ DumpInputs.empty() ? DumpInputFail : *std::max_element(DumpInputs.begin(), DumpInputs.end()); - bool DumpInputFilterOnError = DumpInput == DumpInputFail; + DumpInputFilterValue DumpInputFilter; + if (DumpInputFilters.empty()) + DumpInputFilter = DumpInput == DumpInputAlways ? DumpInputFilterAll + : DumpInputFilterError; + else + DumpInputFilter = + *std::max_element(DumpInputFilters.begin(), DumpInputFilters.end()); unsigned DumpInputContext = DumpInputContexts.empty() ? 5 : *std::max_element(DumpInputContexts.begin(), @@ -799,7 +845,7 @@ unsigned LabelWidth; BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags, Annotations, LabelWidth); - DumpAnnotatedInput(errs(), Req, DumpInputFilterOnError, DumpInputContext, + DumpAnnotatedInput(errs(), Req, DumpInputFilter, DumpInputContext, InputFileText, Annotations, LabelWidth); }