[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