[llvm] r349418 - [FileCheck] Annotate input dump (1/7)
Joel E. Denny via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 29 05:41:53 PST 2018
Hi David,
On Sat, Dec 29, 2018 at 1:17 AM David Blaikie <dblaikie at gmail.com> wrote:
> Hey there - a bunch of these commit messages came through as N/7, all
> otherwise containing an identical description. Could you reply to the
> commit emails with specifics about what was changed in each commit - it'd
> be helpful for future archaeology
>
The commit emails I'm looking at are all different. The structure is
similar, but the details are different. Could you please check again?
> (ideally the specific patch descriptions would be in the specific commits,
> but having the info on the mailing list at least will help some folks).
>
git log shows me different patch descriptions as well.
I'm happy to clarify things, but I'm not yet seeing the problem.
Thanks.
Joel
>
> On Mon, Dec 17, 2018 at 4:04 PM Joel E. Denny via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: jdenny
>> Date: Mon Dec 17 16:01:39 2018
>> New Revision: 349418
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=349418&view=rev
>> Log:
>> [FileCheck] Annotate input dump (1/7)
>>
>> Extend FileCheck to dump its input annotated with FileCheck's
>> diagnostics: errors, good matches if -v, and additional information if
>> -vv. The goal is to make it easier to visualize FileCheck's matching
>> behavior when debugging.
>>
>> Each patch in this series implements input annotations for a
>> particular category of FileCheck diagnostics. While the first few
>> patches alone are somewhat useful, the annotations become much more
>> useful as later patches implement annotations for -v and -vv
>> diagnostics, which show the matching behavior leading up to the error.
>>
>> This first patch implements boilerplate plus input annotations for
>> error diagnostics reporting that no matches were found for a
>> directive. These annotations mark the search ranges of the failed
>> directives. Instead of using the usual `^~~`, which is used by later
>> patches for good matches, these annotations use `X~~` so that this
>> category of errors is visually distinct.
>>
>> For example:
>>
>> ```
>> $ FileCheck -dump-input=help
>> The following description was requested by -dump-input=help to
>> explain the input annotations printed by -dump-input=always and
>> -dump-input=fail:
>>
>> - L: labels line number L of the input file
>> - T:L labels the match result for a pattern of type T from line L of
>> the check file
>> - X~~ marks search range when no match is found
>> - colors error
>>
>> If you are not seeing color above or in input dumps, try: -color
>>
>> $ FileCheck -v -dump-input=always check1 < input1 |& sed -n '/^Input
>> file/,$p'
>> Input file: <stdin>
>> Check file: check1
>>
>> -dump-input=help describes the format of the following dump.
>>
>> Full input was:
>> <<<<<<
>> 1: ; abc def
>> 2: ; ghI jkl
>> next:3 X~~~~~~~~ error: no match found
>> >>>>>>
>>
>> $ cat check1
>> CHECK: abc
>> CHECK-SAME: def
>> CHECK-NEXT: ghi
>> CHECK-SAME: jkl
>>
>> $ cat input1
>> ; abc def
>> ; ghI jkl
>> ```
>>
>> Some additional details related to the boilerplate:
>>
>> * Enabling: The annotated input dump is enabled by `-dump-input`,
>> which can also be set via the `FILECHECK_OPTS` environment variable.
>> Accepted values are `help`, `always`, `fail`, or `never`. As shown
>> above, `help` describes the format of the dump. `always` is helpful
>> when you want to investigate a successful FileCheck run, perhaps for
>> an unexpected pass. `-dump-input-on-failure` and
>> `FILECHECK_DUMP_INPUT_ON_FAILURE` remain as a deprecated alias for
>> `-dump-input=fail`.
>>
>> * Diagnostics: The usual diagnostics are not suppressed in this mode
>> and are printed first. For brevity in the example above, I've
>> omitted them using a sed command. Sometimes they're perfectly
>> sufficient, and then they make debugging quicker than if you were
>> forced to hunt through a dump of long input looking for the error.
>> If you think they'll get in the way sometimes, keep in mind that
>> it's pretty easy to grep for the start of the input dump, which is
>> `<<<`.
>>
>> * Colored Annotations: The annotated input is colored if colors are
>> enabled (enabling colors can be forced using -color). For example,
>> errors are red. However, as in the above example, colors are not
>> vital to reading the annotations.
>>
>> I don't know how to test color in the output, so any hints here would
>> be appreciated.
>>
>> Reviewed By: george.karpenkov, zturner, probinson
>>
>> Differential Revision: https://reviews.llvm.org/D52999
>>
>> Added:
>> llvm/trunk/test/FileCheck/dump-input-annotations.txt
>> llvm/trunk/test/FileCheck/dump-input-enable.txt
>> llvm/trunk/test/FileCheck/no-check-file.txt
>> Removed:
>> llvm/trunk/test/FileCheck/verbose_mode.txt
>> Modified:
>> llvm/trunk/docs/CommandGuide/FileCheck.rst
>> llvm/trunk/include/llvm/Support/FileCheck.h
>> llvm/trunk/lib/Support/FileCheck.cpp
>> llvm/trunk/utils/FileCheck/FileCheck.cpp
>>
>> Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=349418&r1=349417&r2=349418&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)
>> +++ llvm/trunk/docs/CommandGuide/FileCheck.rst Mon Dec 17 16:01:39 2018
>> @@ -80,9 +80,16 @@ and from the command line.
>> -verify``. With this option FileCheck will verify that input does not
>> contain
>> warnings not covered by any ``CHECK:`` patterns.
>>
>> +.. option:: --dump-input <mode>
>> +
>> + Dump input to stderr, adding annotations representing currently enabled
>> + diagnostics. Do this either 'always', on 'fail', or 'never'. Specify
>> 'help'
>> + to explain the dump format and quit.
>> +
>> .. option:: --dump-input-on-failure
>>
>> - When the check fails, dump all of the original input.
>> + When the check fails, dump all of the original input. This option is
>> + deprecated in favor of `--dump-input=fail`.
>>
>> .. option:: --enable-var-scope
>>
>>
>> Modified: llvm/trunk/include/llvm/Support/FileCheck.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=349418&r1=349417&r2=349418&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Support/FileCheck.h (original)
>> +++ llvm/trunk/include/llvm/Support/FileCheck.h Mon Dec 17 16:01:39 2018
>> @@ -82,6 +82,8 @@ public:
>> };
>> }
>>
>> +struct FileCheckDiag;
>> +
>> class FileCheckPattern {
>> SMLoc PatternLoc;
>>
>> @@ -146,6 +148,28 @@ private:
>> };
>>
>>
>> //===----------------------------------------------------------------------===//
>> +/// Summary of a FileCheck diagnostic.
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +struct FileCheckDiag {
>> + /// What is the FileCheck directive for this diagnostic?
>> + Check::FileCheckType CheckTy;
>> + /// Where is the FileCheck directive for this diagnostic?
>> + unsigned CheckLine, CheckCol;
>> + /// What kind of match result does this diagnostic describe?
>> + enum MatchType {
>> + // TODO: More members will appear with later patches in this series.
>> + /// Indicates no match for an expected pattern.
>> + MatchNoneButExpected,
>> + MatchTypeCount,
>> + } MatchTy;
>> + /// The search range.
>> + unsigned InputStartLine, InputStartCol, InputEndLine, InputEndCol;
>> + FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
>> + SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);
>> +};
>> +
>>
>> +//===----------------------------------------------------------------------===//
>> // Check Strings.
>>
>> //===----------------------------------------------------------------------===//
>>
>> @@ -169,7 +193,7 @@ struct FileCheckString {
>>
>> size_t Check(const SourceMgr &SM, StringRef Buffer, bool
>> IsLabelScanMode,
>> size_t &MatchLen, StringMap<StringRef> &VariableTable,
>> - FileCheckRequest &Req) const;
>> + FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags)
>> const;
>>
>> bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
>> bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
>> @@ -180,7 +204,8 @@ struct FileCheckString {
>> size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
>> std::vector<const FileCheckPattern *> &NotStrings,
>> StringMap<StringRef> &VariableTable,
>> - const FileCheckRequest &Req) const;
>> + const FileCheckRequest &Req,
>> + std::vector<FileCheckDiag> *Diags) const;
>> };
>>
>> /// FileCheck class takes the request and exposes various methods that
>> @@ -217,7 +242,8 @@ public:
>> ///
>> /// Returns false if the input fails to satisfy the checks.
>> bool CheckInput(SourceMgr &SM, StringRef Buffer,
>> - ArrayRef<FileCheckString> CheckStrings);
>> + ArrayRef<FileCheckString> CheckStrings,
>> + std::vector<FileCheckDiag> *Diags = nullptr);
>> };
>> } // namespace llvm
>> #endif
>>
>> Modified: llvm/trunk/lib/Support/FileCheck.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Support/FileCheck.cpp (original)
>> +++ llvm/trunk/lib/Support/FileCheck.cpp Mon Dec 17 16:01:39 2018
>> @@ -412,6 +412,21 @@ void FileCheckPattern::PrintVariableUses
>> }
>> }
>>
>> +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) {
>> + 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);
>> + return Range;
>> +}
>> +
>> void FileCheckPattern::PrintFuzzyMatch(
>> const SourceMgr &SM, StringRef Buffer,
>> const StringMap<StringRef> &VariableTable) const {
>> @@ -531,6 +546,22 @@ llvm::FileCheck::CanonicalizeFile(Memory
>> return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);
>> }
>>
>> +FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
>> + const Check::FileCheckType &CheckTy,
>> + SMLoc CheckLoc, MatchType MatchTy,
>> + SMRange InputRange)
>> + : CheckTy(CheckTy), MatchTy(MatchTy) {
>> + auto Start = SM.getLineAndColumn(InputRange.Start);
>> + auto End = SM.getLineAndColumn(InputRange.End);
>> + InputStartLine = Start.first;
>> + InputStartCol = Start.second;
>> + InputEndLine = End.first;
>> + InputEndCol = End.second;
>> + Start = SM.getLineAndColumn(CheckLoc);
>> + CheckLine = Start.first;
>> + CheckCol = Start.second;
>> +}
>> +
>> static bool IsPartOfWord(char c) {
>> return (isalnum(c) || c == '-' || c == '_');
>> }
>> @@ -897,7 +928,8 @@ static void PrintNoMatch(bool ExpectedMa
>> StringRef Prefix, SMLoc Loc,
>> const FileCheckPattern &Pat, int MatchedCount,
>> StringRef Buffer, StringMap<StringRef>
>> &VariableTable,
>> - bool VerboseVerbose) {
>> + bool VerboseVerbose,
>> + std::vector<FileCheckDiag> *Diags) {
>> if (!ExpectedMatch && !VerboseVerbose)
>> return;
>>
>> @@ -915,9 +947,11 @@ static void PrintNoMatch(bool ExpectedMa
>> // Print the "scanning from here" line. If the current position is at
>> the
>> // end of a line, advance to the start of the next line.
>> Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r"));
>> -
>> - SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
>> SourceMgr::DK_Note,
>> - "scanning from here");
>> + SMRange SearchRange = ProcessMatchResult(
>> + ExpectedMatch ? FileCheckDiag::MatchNoneButExpected
>> + : FileCheckDiag::MatchTypeCount,
>> + SM, Loc, Pat.getCheckTy(), Buffer, 0, Buffer.size(), Diags);
>> + SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from
>> here");
>>
>> // Allow the pattern to print additional information if desired.
>> Pat.PrintVariableUses(SM, Buffer, VariableTable);
>> @@ -928,9 +962,10 @@ static void PrintNoMatch(bool ExpectedMa
>> static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
>> const FileCheckString &CheckStr, int
>> MatchedCount,
>> StringRef Buffer, StringMap<StringRef>
>> &VariableTable,
>> - bool VerboseVerbose) {
>> + bool VerboseVerbose,
>> + std::vector<FileCheckDiag> *Diags) {
>> PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc,
>> CheckStr.Pat,
>> - MatchedCount, Buffer, VariableTable, VerboseVerbose);
>> + MatchedCount, Buffer, VariableTable, VerboseVerbose,
>> Diags);
>> }
>>
>> /// Count the number of newlines in the specified range.
>> @@ -958,9 +993,10 @@ static unsigned CountNumNewlinesBetween(
>>
>> /// Match check string and its "not strings" and/or "dag strings".
>> size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
>> - bool IsLabelScanMode, size_t &MatchLen,
>> - StringMap<StringRef> &VariableTable,
>> - FileCheckRequest &Req) const {
>> + bool IsLabelScanMode, size_t &MatchLen,
>> + StringMap<StringRef> &VariableTable,
>> + FileCheckRequest &Req,
>> + std::vector<FileCheckDiag> *Diags) const {
>> size_t LastPos = 0;
>> std::vector<const FileCheckPattern *> NotStrings;
>>
>> @@ -970,7 +1006,7 @@ size_t FileCheckString::Check(const Sour
>> // over the block again (including the last CHECK-LABEL) in normal
>> mode.
>> if (!IsLabelScanMode) {
>> // Match "dag strings" (with mixed "not strings" if any).
>> - LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req);
>> + LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req,
>> Diags);
>> if (LastPos == StringRef::npos)
>> return StringRef::npos;
>> }
>> @@ -992,7 +1028,7 @@ size_t FileCheckString::Check(const Sour
>> // report
>> if (MatchPos == StringRef::npos) {
>> PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable,
>> - Req.VerboseVerbose);
>> + Req.VerboseVerbose, Diags);
>> return StringRef::npos;
>> }
>> PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,
>> @@ -1116,7 +1152,7 @@ bool FileCheckString::CheckNot(const Sou
>>
>> if (Pos == StringRef::npos) {
>> PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
>> - VariableTable, Req.VerboseVerbose);
>> + VariableTable, Req.VerboseVerbose, nullptr);
>> continue;
>> }
>>
>> @@ -1130,10 +1166,12 @@ bool FileCheckString::CheckNot(const Sou
>> }
>>
>> /// Match "dag strings" and their mixed "not strings".
>> -size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
>> - std::vector<const FileCheckPattern *>
>> &NotStrings,
>> - StringMap<StringRef> &VariableTable,
>> - const FileCheckRequest &Req) const {
>> +size_t
>> +FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
>> + std::vector<const FileCheckPattern *>
>> &NotStrings,
>> + StringMap<StringRef> &VariableTable,
>> + const FileCheckRequest &Req,
>> + std::vector<FileCheckDiag> *Diags) const {
>> if (DagNotStrings.empty())
>> return 0;
>>
>> @@ -1177,7 +1215,7 @@ size_t FileCheckString::CheckDag(const S
>> // that group of CHECK-DAGs fails immediately.
>> if (MatchPosBuf == StringRef::npos) {
>> PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
>> - VariableTable, Req.VerboseVerbose);
>> + VariableTable, Req.VerboseVerbose, Diags);
>> return StringRef::npos;
>> }
>> // Re-calc it as the offset relative to the start of the original
>> string.
>> @@ -1318,7 +1356,8 @@ static void ClearLocalVars(StringMap<Str
>> ///
>> /// Returns false if the input fails to satisfy the checks.
>> bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
>> - ArrayRef<FileCheckString> CheckStrings) {
>> + ArrayRef<FileCheckString> CheckStrings,
>> + std::vector<FileCheckDiag> *Diags) {
>> bool ChecksFailed = false;
>>
>> /// VariableTable - This holds all the current filecheck variables.
>> @@ -1341,9 +1380,8 @@ bool llvm::FileCheck::CheckInput(SourceM
>>
>> // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
>> size_t MatchLabelLen = 0;
>> - size_t MatchLabelPos =
>> - CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen,
>> VariableTable,
>> - Req);
>> + size_t MatchLabelPos = CheckLabelStr.Check(
>> + SM, Buffer, true, MatchLabelLen, VariableTable, Req, Diags);
>> if (MatchLabelPos == StringRef::npos)
>> // Immediately bail of CHECK-LABEL fails, nothing else we can do.
>> return false;
>> @@ -1362,8 +1400,8 @@ bool llvm::FileCheck::CheckInput(SourceM
>> // Check each string within the scanned region, including a second
>> check
>> // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
>> size_t MatchLen = 0;
>> - size_t MatchPos =
>> - CheckStr.Check(SM, CheckRegion, false, MatchLen,
>> VariableTable, Req);
>> + size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,
>> + VariableTable, Req, Diags);
>>
>> if (MatchPos == StringRef::npos) {
>> ChecksFailed = true;
>>
>> Added: llvm/trunk/test/FileCheck/dump-input-annotations.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-annotations.txt?rev=349418&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/FileCheck/dump-input-annotations.txt (added)
>> +++ llvm/trunk/test/FileCheck/dump-input-annotations.txt Mon Dec 17
>> 16:01:39 2018
>> @@ -0,0 +1,241 @@
>> +;--------------------------------------------------
>> +; Use -strict-whitespace to check marker alignment here.
>> +; (Also check multiline marker where start/end columns vary across
>> lines.)
>> +;
>> +; In the remaining checks, don't use -strict-whitespace and thus check
>> just the
>> +; presence, order, and lengths of markers. That way, if we ever change
>> padding
>> +; within line labels, we don't have to adjust so many tests.
>> +;--------------------------------------------------
>> +
>> +; RUN: echo 'hello world' > %t.in
>> +; RUN: echo 'goodbye' >> %t.in
>> +; RUN: echo 'world' >> %t.in
>> +
>> +; RUN: echo 'CHECK: hello' > %t.chk
>> +; RUN: echo 'CHECK: universe' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -strict-whitespace -match-full-lines
>> -check-prefix=ALIGN %s
>> +
>> +; ALIGN:Full input was:
>> +; ALIGN-NEXT:<<<<<<
>> +; ALIGN-NEXT: 1: hello world
>> +; ALIGN-NEXT:check:2 X~~~~
>> +; ALIGN-NEXT: 2: goodbye
>> +; ALIGN-NEXT:check:2 ~~~~~~~
>> +; ALIGN-NEXT: 3: world
>> +; ALIGN-NEXT:check:2 ~~~~~ error: no match found
>> +; ALIGN-NEXT:>>>>>>
>> +; ALIGN-NOT:{{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK (also: multi-line search range)
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +
>> +; RUN: echo 'hello' > %t.in
>> +; RUN: echo 'again' >> %t.in
>> +; RUN: echo 'whirled' >> %t.in
>> +
>> +; RUN: echo 'CHECK: hello' > %t.chk
>> +; RUN: echo 'CHECK: world' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefix=CHK
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=CHK,CHK-V
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=CHK,CHK-V
>> +
>> +; CHK: <<<<<<
>> +; CHK-NEXT: 1: hello
>> +; CHK-NEXT: 2: again
>> +; CHK-NEXT: check:2 X~~~~
>> +; CHK-NEXT: 3: whirled
>> +; CHK-NEXT: check:2 ~~~~~~~ error: no match found
>> +; CHK-NEXT: >>>>>>
>> +; CHK-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-COUNT-<num>
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +
>> +; RUN: echo 'pete' > %t.in
>> +; RUN: echo 'repete' >> %t.in
>> +; RUN: echo 'repeat' >> %t.in
>> +
>> +; 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: 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: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-NEXT (also: EOF search-range)
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +
>> +; RUN: echo 'hello' > %t.in
>> +; RUN: echo 'again' >> %t.in
>> +
>> +; RUN: echo 'CHECK: hello' > %t.chk
>> +; RUN: echo 'CHECK-NEXT: again' >> %t.chk
>> +; RUN: echo 'CHECK-NEXT: world' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefix=NXT
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=NXT,NXT-V
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; 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: >>>>>>
>> +; NXT-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-SAME (also: single-char search range)
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +
>> +; RUN: echo 'hello world!' > %t.in
>> +
>> +; RUN: echo 'CHECK: hello' > %t.chk
>> +; RUN: echo 'CHECK-SAME: world' >> %t.chk
>> +; RUN: echo 'CHECK-SAME: again' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefix=SAM
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=SAM,SAM-V
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; 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: >>>>>>
>> +; SAM-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-EMPTY (also: search range ends at label)
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +;
>> +; CHECK-EMPTY always seems to match an empty line at EOF (illegally when
>> it's
>> +; not the next line) unless either (1) the last line is non-empty and
>> has no
>> +; newline or (2) there's a CHECK-LABEL to end the search range before
>> EOF. We
>> +; choose scenario 2 to check the case of no match.
>> +
>> +; RUN: echo 'hello' > %t.in
>> +; RUN: echo '' >> %t.in
>> +; RUN: echo 'world' >> %t.in
>> +; RUN: echo 'label' >> %t.in
>> +
>> +; RUN: echo 'CHECK: hello' > %t.chk
>> +; RUN: echo 'CHECK-EMPTY:' >> %t.chk
>> +; RUN: echo 'CHECK-EMPTY:' >> %t.chk
>> +; RUN: echo 'CHECK-LABEL: label' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefix=EMP
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP,EMP-V
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=EMP,EMP-V,EMP-VV
>> +
>> +; EMP: <<<<<<
>> +; EMP-NEXT: 1: hello
>> +; EMP-NEXT: 2:
>> +; EMP-NEXT: 3: world
>> +; EMP-NEXT: empty:3 X~~~~
>> +; EMP-NEXT: 4: label
>> +; EMP-NEXT: empty:3 ~~~~~ error: no match found
>> +; EMP-NEXT: >>>>>>
>> +; EMP-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-DAG
>> +;--------------------------------------------------
>> +
>> +; Good match, discarded match plus good match, and no match.
>> +
>> +; RUN: echo 'abc' > %t.in
>> +; RUN: echo 'def' >> %t.in
>> +; RUN: echo 'abc' >> %t.in
>> +
>> +; RUN: echo 'CHECK-DAG: def' > %t.chk
>> +; RUN: echo 'CHECK-DAG: abc' >> %t.chk
>> +; RUN: echo 'CHECK-DAG: abc' >> %t.chk
>> +; 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: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=DAG
>> +
>> +; DAG: <<<<<<
>> +; DAG-NEXT: 1: abc
>> +; DAG-NEXT: 2: def
>> +; DAG-NEXT: 3: abc
>> +; DAG-NEXT: dag:4 X~~ error: no match found
>> +; DAG-NEXT: >>>>>>
>> +; DAG-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; CHECK-LABEL
>> +;--------------------------------------------------
>> +
>> +; Good match and no match.
>> +
>> +; RUN: echo 'lab0' > %t.in
>> +; RUN: echo 'foo' >> %t.in
>> +; RUN: echo 'lab1' >> %t.in
>> +; RUN: echo 'bar' >> %t.in
>> +
>> +; RUN: echo 'CHECK-LABEL: lab0' > %t.chk
>> +; RUN: echo 'CHECK: foo' >> %t.chk
>> +; RUN: echo 'CHECK-LABEL: lab2' >> %t.chk
>> +
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -v
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB,LAB-V
>> +; RUN: not FileCheck -dump-input=always -input-file %t.in %t.chk -vv
>> 2>&1 \
>> +; RUN: | FileCheck -match-full-lines %s -check-prefixes=LAB,LAB-V,LAB-VV
>> +
>> +; LAB: <<<<<<
>> +; LAB-NEXT: 1: lab0
>> +; LAB-NEXT: 2: foo
>> +; LAB-NEXT: label:3 X~~
>> +; LAB-NEXT: 3: lab1
>> +; LAB-NEXT: label:3 ~~~~
>> +; LAB-NEXT: 4: bar
>> +; LAB-NEXT: label:3 ~~~ error: no match found
>> +; LAB-NEXT: >>>>>>
>> +; LAB-NOT: {{.}}
>> +
>> +
>>
>> Added: llvm/trunk/test/FileCheck/dump-input-enable.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/dump-input-enable.txt?rev=349418&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/FileCheck/dump-input-enable.txt (added)
>> +++ llvm/trunk/test/FileCheck/dump-input-enable.txt Mon Dec 17 16:01:39
>> 2018
>> @@ -0,0 +1,126 @@
>> +; RUN: echo ciao > %t.good
>> +; RUN: echo world >> %t.good
>> +
>> +; RUN: echo hello > %t.err
>> +; RUN: echo world >> %t.err
>> +
>> +; RUN: echo 'CHECK: ciao' > %t.check
>> +; RUN: echo 'CHECK-NEXT: world' >> %t.check
>> +
>> +;--------------------------------------------------
>> +; unknown value
>> +;--------------------------------------------------
>> +
>> +; RUN: not FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=foobar 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL
>> +
>> +; No positional arg.
>> +; RUN: not FileCheck -dump-input=foobar 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=BADVAL
>> +
>> +BADVAL: FileCheck: for the -dump-input option: Cannot find option named
>> 'foobar'!
>> +
>> +;--------------------------------------------------
>> +; help
>> +;--------------------------------------------------
>> +
>> +; Appended to normal command line.
>> +; RUN: FileCheck -input-file %t.err -color %t.check -dump-input=help \
>> +; RUN: | FileCheck %s -check-prefix=HELP
>> +
>> +; No positional arg.
>> +; RUN: FileCheck -dump-input=help | FileCheck %s -check-prefix=HELP
>> +
>> +HELP-NOT: {{.}}
>> +HELP: The following description was requested by -dump-input=help
>> +HELP: try{{.*}}-color
>> +HELP-NOT: {{.}}
>> +
>> +;--------------------------------------------------
>> +; never
>> +;--------------------------------------------------
>> +
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=never 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> -allow-empty
>> +
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=never 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> +
>> +;--------------------------------------------------
>> +; default: never
>> +;--------------------------------------------------
>> +
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> -allow-empty
>> +
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> +
>> +;--------------------------------------------------
>> +; fail
>> +;--------------------------------------------------
>> +
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=fail 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> -allow-empty
>> +
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=fail 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR
>> +
>> +;--------------------------------------------------
>> +; -dump-input-on-failure
>> +;--------------------------------------------------
>> +
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input-on-failure 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> -allow-empty
>> +
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input-on-failure 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR
>> +
>> +; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 \
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-NODUMP
>> -allow-empty
>> +
>> +; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 \
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR
>> +
>> +;--------------------------------------------------
>> +; always
>> +;--------------------------------------------------
>> +
>> +; RUN: FileCheck -input-file %t.good %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=always -v 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-GOOD
>> +
>> +; RUN: not FileCheck -input-file %t.err %t.check -check-prefix=CHECK \
>> +; RUN: -match-full-lines -dump-input=always 2>&1 \
>> +; RUN: | FileCheck %s -match-full-lines -check-prefix=CHECK-ERR
>> +
>> +; END.
>> +
>> +; CHECK-GOOD: Full input was:
>> +; CHECK-GOOD-NEXT: <<<<<<
>> +; CHECK-GOOD-NEXT: 1: ciao
>> +; CHECK-GOOD-NEXT: 2: world
>> +; CHECK-GOOD-NEXT: >>>>>>
>> +
>> +; CHECK-ERR: Full input was:
>> +; CHECK-ERR-NEXT: <<<<<<
>> +; CHECK-ERR-NEXT: 1: hello
>> +; CHECK-ERR-NEXT: check:1 X~~~~
>> +; CHECK-ERR-NEXT: 2: world
>> +; CHECK-ERR-NEXT: check:1 ~~~~~ error: no match found
>> +; CHECK-ERR-NEXT: >>>>>>
>> +
>> +; CHECK-NODUMP-NOT: <<<<<<
>>
>> Added: llvm/trunk/test/FileCheck/no-check-file.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/no-check-file.txt?rev=349418&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/FileCheck/no-check-file.txt (added)
>> +++ llvm/trunk/test/FileCheck/no-check-file.txt Mon Dec 17 16:01:39 2018
>> @@ -0,0 +1,3 @@
>> +; RUN: not FileCheck 2>&1 | FileCheck %s
>> +
>> +CHECK: <check-file> not specified
>>
>> Removed: llvm/trunk/test/FileCheck/verbose_mode.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/verbose_mode.txt?rev=349417&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/FileCheck/verbose_mode.txt (original)
>> +++ llvm/trunk/test/FileCheck/verbose_mode.txt (removed)
>> @@ -1,17 +0,0 @@
>> -; RUN: not FileCheck -input-file %s %s --check-prefix=CHECK1
>> --match-full-lines --dump-input-on-failure 2>&1 | FileCheck %s
>> --check-prefix=CHECKERROR --match-full-lines
>> -; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 not FileCheck -input-file
>> %s %s --check-prefix=CHECK1 --match-full-lines 2>&1 | FileCheck %s
>> --check-prefix=CHECKERROR --match-full-lines
>> -; RUN: env FILECHECK_DUMP_INPUT_ON_FAILURE=1 not FileCheck -input-file
>> %s %s --check-prefix=CHECK1 --match-full-lines --dump-input-on-failure=0
>> 2>&1 | FileCheck %s --check-prefix=CHECKERRORNOVERBOSE --match-full-lines
>> -
>> -hello
>> -world
>> -
>> -; CHECK1: ciao
>> -; CHECK1-NEXT: world
>> -
>> -; CHECKERROR: Full input was:
>> -; CHECKERROR-NEXT: <<<<<<
>> -; CHECKERROR: hello
>> -; CHECKERROR: world
>> -; CHECKERROR: >>>>>>
>> -
>> -; CHECKERRORNOVERBOSE-NOT: <<<<<<
>>
>> Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=349418&r1=349417&r2=349418&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)
>> +++ llvm/trunk/utils/FileCheck/FileCheck.cpp Mon Dec 17 16:01:39 2018
>> @@ -19,12 +19,13 @@
>> #include "llvm/Support/CommandLine.h"
>> #include "llvm/Support/InitLLVM.h"
>> #include "llvm/Support/Process.h"
>> +#include "llvm/Support/WithColor.h"
>> #include "llvm/Support/raw_ostream.h"
>> #include "llvm/Support/FileCheck.h"
>> using namespace llvm;
>>
>> static cl::opt<std::string>
>> - CheckFilename(cl::Positional, cl::desc("<check-file>"),
>> cl::Required);
>> + CheckFilename(cl::Positional, cl::desc("<check-file>"),
>> cl::Optional);
>>
>> static cl::opt<std::string>
>> InputFilename("input-file", cl::desc("File to check (defaults to
>> stdin)"),
>> @@ -91,7 +92,27 @@ static cl::opt<bool> DumpInputOnFailure(
>> "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv)),
>> cl::desc("Dump original input to stderr before failing.\n"
>> "The value can be also controlled using\n"
>> - "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"));
>> + "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
>> + "This option is deprecated in favor of
>> -dump-input=fail.\n"));
>> +
>> +enum DumpInputValue {
>> + DumpInputDefault,
>> + DumpInputHelp,
>> + DumpInputNever,
>> + DumpInputFail,
>> + DumpInputAlways
>> +};
>> +
>> +static cl::opt<DumpInputValue> DumpInput(
>> + "dump-input", cl::init(DumpInputDefault),
>> + cl::desc("Dump input to stderr, adding annotations representing\n"
>> + " currently enabled diagnostics\n"),
>> + cl::value_desc("mode"),
>> + cl::values(clEnumValN(DumpInputHelp, "help",
>> + "Explain dump format and quit"),
>> + clEnumValN(DumpInputNever, "never", "Never dump input"),
>> + clEnumValN(DumpInputFail, "fail", "Dump input on
>> failure"),
>> + clEnumValN(DumpInputAlways, "always", "Always dump
>> input")));
>>
>> typedef cl::list<std::string>::const_iterator prefix_iterator;
>>
>> @@ -108,6 +129,269 @@ static void DumpCommandLine(int argc, ch
>> errs() << "\n";
>> }
>>
>> +struct MarkerStyle {
>> + /// The starting char (before tildes) for marking the line.
>> + char Lead;
>> + /// What color to use for this annotation.
>> + raw_ostream::Colors Color;
>> + /// 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)
>> + : Lead(Lead), Color(Color), Note(Note) {}
>> +};
>> +
>> +static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
>> + switch (MatchTy) {
>> + case FileCheckDiag::MatchNoneButExpected:
>> + return MarkerStyle('X', raw_ostream::RED, "error: no match found");
>> + case FileCheckDiag::MatchTypeCount:
>> + llvm_unreachable_internal("unexpected match type");
>> + }
>> + llvm_unreachable_internal("unexpected match type");
>> +}
>> +
>> +static void DumpInputAnnotationHelp(raw_ostream &OS) {
>> + OS << "The following description was requested by -dump-input=help
>> to\n"
>> + << "explain the input annotations printed by -dump-input=always
>> and\n"
>> + << "-dump-input=fail:\n\n";
>> +
>> + // Labels for input lines.
>> + OS << " - ";
>> + WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
>> + OS << " labels line number L of the input file\n";
>> +
>> + // Labels for annotation lines.
>> + OS << " - ";
>> + WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
>> + OS << " labels the match result for a pattern of type T from "
>> + << "line L of\n"
>> + << " the check file\n";
>> +
>> + // Markers on annotation lines.
>> + OS << " - ";
>> + WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
>> + OS << " marks search range when no match is found\n";
>> +
>> + // Colors.
>> + OS << " - colors ";
>> + WithColor(OS, raw_ostream::RED, true) << "error";
>> + OS << "\n\n"
>> + << "If you are not seeing color above or in input dumps, try:
>> -color\n";
>> +}
>> +
>> +/// An annotation for a single input line.
>> +struct InputAnnotation {
>> + /// The check file line (one-origin indexing) where the directive that
>> + /// produced this annotation is located.
>> + unsigned CheckLine;
>> + /// The label for this annotation.
>> + std::string Label;
>> + /// What input line (one-origin indexing) this annotation marks. This
>> might
>> + /// be different from the starting line of the original diagnostic if
>> this is
>> + /// a non-initial fragment of a diagnostic that has been broken across
>> + /// multiple lines.
>> + unsigned InputLine;
>> + /// The column range (one-origin indexing, open end) in which to to
>> mark the
>> + /// input line. If InputEndCol is UINT_MAX, treat it as the last
>> column
>> + /// before the newline.
>> + unsigned InputStartCol, InputEndCol;
>> + /// The marker to use.
>> + MarkerStyle Marker;
>> +};
>> +
>> +/// Get an abbreviation for the check type.
>> +std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
>> + switch (Ty) {
>> + case Check::CheckPlain:
>> + if (Ty.getCount() > 1)
>> + return "count";
>> + return "check";
>> + case Check::CheckNext:
>> + return "next";
>> + case Check::CheckSame:
>> + return "same";
>> + case Check::CheckNot:
>> + return "not";
>> + case Check::CheckDAG:
>> + return "dag";
>> + case Check::CheckLabel:
>> + return "label";
>> + case Check::CheckEmpty:
>> + return "empty";
>> + case Check::CheckEOF:
>> + return "eof";
>> + case Check::CheckBadNot:
>> + return "bad-not";
>> + case Check::CheckBadCount:
>> + return "bad-count";
>> + case Check::CheckNone:
>> + llvm_unreachable("invalid FileCheckType");
>> + }
>> + llvm_unreachable("unknown FileCheckType");
>> +}
>> +
>> +static void BuildInputAnnotations(const std::vector<FileCheckDiag>
>> &Diags,
>> + std::vector<InputAnnotation>
>> &Annotations,
>> + unsigned &LabelWidth) {
>> + // What's the widest label?
>> + LabelWidth = 0;
>> + for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr !=
>> DiagEnd;
>> + ++DiagItr) {
>> + InputAnnotation A;
>> +
>> + // Build label, which uniquely identifies this check result.
>> + A.CheckLine = DiagItr->CheckLine;
>> + llvm::raw_string_ostream Label(A.Label);
>> + Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
>> + << DiagItr->CheckLine;
>> + Label.flush();
>> + LabelWidth = std::max((std::string::size_type)LabelWidth,
>> A.Label.size());
>> +
>> + MarkerStyle Marker = GetMarker(DiagItr->MatchTy);
>> + A.Marker = Marker;
>> +
>> + // Compute the mark location, and break annotation into multiple
>> + // annotations if it spans multiple lines.
>> + A.InputLine = DiagItr->InputStartLine;
>> + A.InputStartCol = DiagItr->InputStartCol;
>> + if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
>> + // Sometimes ranges are empty in order to indicate a specific
>> point, but
>> + // that would mean nothing would be marked, so adjust the range to
>> + // include the following character.
>> + A.InputEndCol =
>> + std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
>> + Annotations.push_back(A);
>> + } else {
>> + assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
>> + "expected input range not to be inverted");
>> + A.InputEndCol = UINT_MAX;
>> + A.Marker.Note = "";
>> + Annotations.push_back(A);
>> + for (unsigned L = DiagItr->InputStartLine + 1, E =
>> DiagItr->InputEndLine;
>> + L <= E; ++L) {
>> + // If a range ends before the first column on a line, then it
>> has no
>> + // characters on that line, so there's nothing to render.
>> + if (DiagItr->InputEndCol == 1 && L == E) {
>> + Annotations.back().Marker.Note = Marker.Note;
>> + break;
>> + }
>> + InputAnnotation B;
>> + B.CheckLine = A.CheckLine;
>> + B.Label = A.Label;
>> + B.InputLine = L;
>> + B.Marker = Marker;
>> + B.Marker.Lead = '~';
>> + B.InputStartCol = 1;
>> + if (L != E) {
>> + B.InputEndCol = UINT_MAX;
>> + B.Marker.Note = "";
>> + } else
>> + B.InputEndCol = DiagItr->InputEndCol;
>> + Annotations.push_back(B);
>> + }
>> + }
>> + }
>> +}
>> +
>> +static void DumpAnnotatedInput(
>> + raw_ostream &OS, StringRef InputFileText,
>> + std::vector<InputAnnotation> &Annotations, unsigned LabelWidth) {
>> + OS << "Full input was:\n<<<<<<\n";
>> +
>> + // Sort annotations.
>> + //
>> + // First, sort in the order of input lines to make it easier to find
>> relevant
>> + // annotations while iterating input lines in the implementation below.
>> + // FileCheck diagnostics are not always reported and recorded in the
>> order of
>> + // input lines due to, for example, CHECK-DAG and CHECK-NOT.
>> + //
>> + // Second, for annotations for the same input line, sort in the order
>> of the
>> + // FileCheck directive's line in the check file (where there's at most
>> one
>> + // directive per line). The rationale of this choice is that, for any
>> input
>> + // line, this sort establishes a total order of annotations that, with
>> + // respect to match results, is consistent across multiple lines, thus
>> + // making match results easier to track from one line to the next when
>> they
>> + // span multiple lines.
>> + std::sort(Annotations.begin(), Annotations.end(),
>> + [](const InputAnnotation &A, const InputAnnotation &B) {
>> + if (A.InputLine != B.InputLine)
>> + return A.InputLine < B.InputLine;
>> + return A.CheckLine < B.CheckLine;
>> + });
>> +
>> + // Compute the width of the label column.
>> + const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
>> + *InputFileEnd = InputFileText.bytes_end();
>> + unsigned LineCount = InputFileText.count('\n');
>> + if (InputFileEnd[-1] != '\n')
>> + ++LineCount;
>> + unsigned LineNoWidth = log10(LineCount) + 1;
>> + // +3 below adds spaces (1) to the left of the (right-aligned) line
>> numbers
>> + // on input lines and (2) to the right of the (left-aligned) labels on
>> + // annotation lines so that input lines and annotation lines are more
>> + // visually distinct. For example, the spaces on the annotation lines
>> ensure
>> + // that input line numbers and check directive line numbers never align
>> + // horizontally. Those line numbers might not even be for the same
>> file.
>> + // One space would be enough to achieve that, but more makes it even
>> easier
>> + // to see.
>> + LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
>> +
>> + // Print annotated input lines.
>> + auto AnnotationItr = Annotations.begin(), AnnotationEnd =
>> Annotations.end();
>> + for (unsigned Line = 1;
>> + InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
>> + ++Line) {
>> + const unsigned char *InputFileLine = InputFilePtr;
>> +
>> + // Print right-aligned line number.
>> + WithColor(OS, raw_ostream::BLACK, true)
>> + << format_decimal(Line, LabelWidth) << ": ";
>> +
>> + // Print numbered line.
>> + bool Newline = false;
>> + while (InputFilePtr != InputFileEnd && !Newline) {
>> + if (*InputFilePtr == '\n')
>> + Newline = true;
>> + else
>> + OS << *InputFilePtr;
>> + ++InputFilePtr;
>> + }
>> + OS << '\n';
>> + unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
>> +
>> + // Print any annotations.
>> + while (AnnotationItr != AnnotationEnd &&
>> + AnnotationItr->InputLine == Line) {
>> + WithColor COS(OS, AnnotationItr->Marker.Color, true);
>> + // The two spaces below are where the ": " appears on input lines.
>> + COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
>> + unsigned Col;
>> + for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
>> + COS << ' ';
>> + COS << AnnotationItr->Marker.Lead;
>> + // If InputEndCol=UINT_MAX, stop at InputLineWidth.
>> + for (++Col; Col < AnnotationItr->InputEndCol && Col <=
>> InputLineWidth;
>> + ++Col)
>> + COS << '~';
>> + const std::string &Note = AnnotationItr->Marker.Note;
>> + if (!Note.empty()) {
>> + // Put the note at the end of the input line. If we were to
>> instead
>> + // put the note right after the marker, subsequent annotations
>> for the
>> + // same input line might appear to mark this note instead of the
>> input
>> + // line.
>> + for (; Col <= InputLineWidth; ++Col)
>> + COS << ' ';
>> + COS << ' ' << Note;
>> + }
>> + COS << '\n';
>> + ++AnnotationItr;
>> + }
>> + }
>> +
>> + OS << ">>>>>>\n";
>> +}
>> +
>> int main(int argc, char **argv) {
>> // Enable use of ANSI color codes because FileCheck is using them to
>> // highlight text.
>> @@ -116,6 +400,14 @@ int main(int argc, char **argv) {
>> InitLLVM X(argc, argv);
>> cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/
>> nullptr,
>> "FILECHECK_OPTS");
>> + if (DumpInput == DumpInputHelp) {
>> + DumpInputAnnotationHelp(outs());
>> + return 0;
>> + }
>> + if (CheckFilename.empty()) {
>> + errs() << "<check-file> not specified\n";
>> + return 2;
>> + }
>>
>> FileCheckRequest Req;
>> for (auto Prefix : CheckPrefixes)
>> @@ -157,7 +449,6 @@ int main(int argc, char **argv) {
>> return 2;
>> }
>>
>> -
>> SourceMgr SM;
>>
>> // Read the expected strings from the check file.
>> @@ -204,10 +495,29 @@ int main(int argc, char **argv) {
>> InputFileText,
>> InputFile.getBufferIdentifier()),
>> SMLoc());
>>
>> - int ExitCode =
>> - FC.CheckInput(SM, InputFileText, CheckStrings) ? EXIT_SUCCESS : 1;
>> - if (ExitCode == 1 && DumpInputOnFailure)
>> - errs() << "Full input was:\n<<<<<<\n" << InputFileText <<
>> "\n>>>>>>\n";
>> + if (DumpInput == DumpInputDefault)
>> + DumpInput = DumpInputOnFailure ? DumpInputFail : DumpInputNever;
>> +
>> + std::vector<FileCheckDiag> Diags;
>> + int ExitCode = FC.CheckInput(SM, InputFileText, CheckStrings,
>> + DumpInput == DumpInputNever ? nullptr :
>> &Diags)
>> + ? EXIT_SUCCESS
>> + : 1;
>> + if (DumpInput == DumpInputAlways ||
>> + (ExitCode == 1 && DumpInput == DumpInputFail)) {
>> + errs() << "\n"
>> + << "Input file: "
>> + << (InputFilename == "-" ? "<stdin>" :
>> InputFilename.getValue())
>> + << "\n"
>> + << "Check file: " << CheckFilename << "\n"
>> + << "\n"
>> + << "-dump-input=help describes the format of the following
>> dump.\n"
>> + << "\n";
>> + std::vector<InputAnnotation> Annotations;
>> + unsigned LabelWidth;
>> + BuildInputAnnotations(Diags, Annotations, LabelWidth);
>> + DumpAnnotatedInput(errs(), InputFileText, Annotations, LabelWidth);
>> + }
>>
>> return ExitCode;
>> }
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20181229/d9671885/attachment-0001.html>
More information about the llvm-commits
mailing list