Skip to content

Commit

Permalink
[FileCheck] Fix --dump-input implicit pattern location
Browse files Browse the repository at this point in the history
Currently, `--dump-input` implies that all `--implicit-check-not`
patterns appear on line 1 by printing annotations like:

```
       1: foo bar baz
not:1         !~~     error: no match expected
```

This patch changes that to:

```
          1: foo bar baz
not:imp1         !~~     error: no match expected
```

`imp1` indicates the first `--implicit-check-not` pattern.

Reviewed By: thopre

Differential Revision: https://reviews.llvm.org/D77605
  • Loading branch information
jdenny-ornl committed Apr 16, 2020
1 parent 86478d3 commit b5a2461
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 27 deletions.
10 changes: 8 additions & 2 deletions llvm/include/llvm/Support/FileCheck.h
Expand Up @@ -88,7 +88,7 @@ struct FileCheckDiag {
/// What is the FileCheck directive for this diagnostic?
Check::FileCheckType CheckTy;
/// Where is the FileCheck directive for this diagnostic?
unsigned CheckLine, CheckCol;
SMLoc CheckLoc;
/// What type of match result does this diagnostic describe?
///
/// A directive's supplied pattern is said to be either expected or excluded
Expand Down Expand Up @@ -160,7 +160,13 @@ class FileCheck {
///
/// Only expected strings whose prefix is one of those listed in \p PrefixRE
/// are recorded. \returns true in case of an error, false otherwise.
bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE);
///
/// If \p ImpPatBufferIDRange, then the range (inclusive start, exclusive end)
/// of IDs for source buffers added to \p SM for implicit patterns are
/// recorded in it. The range is empty if there are none.
bool
readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
std::pair<unsigned, unsigned> *ImpPatBufferIDRange = nullptr);

bool ValidateCheckPrefixes();

Expand Down
25 changes: 18 additions & 7 deletions llvm/lib/Support/FileCheck.cpp
Expand Up @@ -1069,16 +1069,13 @@ FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
const Check::FileCheckType &CheckTy,
SMLoc CheckLoc, MatchType MatchTy,
SMRange InputRange)
: CheckTy(CheckTy), MatchTy(MatchTy) {
: CheckTy(CheckTy), CheckLoc(CheckLoc), 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) {
Expand Down Expand Up @@ -1269,8 +1266,12 @@ FileCheck::FileCheck(FileCheckRequest Req)

FileCheck::~FileCheck() = default;

bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
Regex &PrefixRE) {
bool FileCheck::readCheckFile(
SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
std::pair<unsigned, unsigned> *ImpPatBufferIDRange) {
if (ImpPatBufferIDRange)
ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0;

Error DefineError =
PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
if (DefineError) {
Expand All @@ -1291,7 +1292,17 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,

StringRef PatternInBuffer =
CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
if (ImpPatBufferIDRange) {
if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) {
ImpPatBufferIDRange->first = BufferID;
ImpPatBufferIDRange->second = BufferID + 1;
} else {
assert(BufferID == ImpPatBufferIDRange->second &&
"expected consecutive source buffer IDs");
++ImpPatBufferIDRange->second;
}
}

ImplicitNegativeChecks.push_back(
Pattern(Check::CheckNot, PatternContext.get()));
Expand Down
61 changes: 61 additions & 0 deletions llvm/test/FileCheck/dump-input-annotations.txt
Expand Up @@ -494,3 +494,64 @@
; LAB-NEXT: label:3'0 ~~~
; LAB-NEXT: >>>>>>
; LAB-NOT: {{.}}

;--------------------------------------------------
; --implicit-check-not
;
; The first two --implicit-check-not patterns have no match (success). The
; third has an unexpected match (error). To check per-input-line annotation
; sorting, all of those plus the CHECK directives have annotations on the same
; input line.
;--------------------------------------------------

; RUN: echo 'hello world again!' > %t.in

; RUN: echo 'CHECK: hel' > %t.chk
; RUN: echo 'CHECK: wor' >> %t.chk
; RUN: echo 'CHECK: !' >> %t.chk

; RUN: %ProtectFileCheckOutput \
; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk 2>&1 \
; RUN: --implicit-check-not='goodbye' \
; RUN: --implicit-check-not='world' \
; RUN: --implicit-check-not='again' \
; RUN: | FileCheck -match-full-lines %s -check-prefix=IMPNOT \
; RUN: -implicit-check-not='remark:'
; RUN: %ProtectFileCheckOutput \
; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk -v 2>&1 \
; RUN: --implicit-check-not='goodbye' \
; RUN: --implicit-check-not='world' \
; RUN: --implicit-check-not='again' \
; RUN: | FileCheck -match-full-lines %s -check-prefixes=IMPNOT,IMPNOT-V \
; RUN: -implicit-check-not='remark:'
; RUN: %ProtectFileCheckOutput \
; RUN: not FileCheck -dump-input=always -input-file=%t.in %t.chk -vv 2>&1 \
; RUN: --implicit-check-not='goodbye' \
; RUN: --implicit-check-not='world' \
; RUN: --implicit-check-not='again' \
; RUN: | FileCheck -match-full-lines %s \
; RUN: -check-prefixes=IMPNOT,IMPNOT-V,IMPNOT-VV \
; RUN: -implicit-check-not='remark:'

; Verbose diagnostics are suppressed but not errors.
; IMPNOT:{{.*}}error:{{.*}}

; FIXME: All occurrences of imp1, imp2, and imp3 are sorting after the first
; directive. They should instead be sorted by when they execute.

; IMPNOT:<<<<<<
; IMPNOT-NEXT: 1: hello world again!
; IMPNOT-V-NEXT:check:1 ^~~
; IMPNOT-VV-NEXT:not:imp1 X
; IMPNOT-VV-NEXT:not:imp2 X
; IMPNOT-VV-NEXT:not:imp3 X
; IMPNOT-VV-NEXT:not:imp1 X~~
; IMPNOT-VV-NEXT:not:imp2 X~~
; IMPNOT-VV-NEXT:not:imp3 X~~
; IMPNOT-VV-NEXT:not:imp1 X~~~~~~~
; IMPNOT-VV-NEXT:not:imp2 X~~~~~~~
; IMPNOT-NEXT:not:imp3 !~~~~ error: no match expected
; IMPNOT-V-NEXT:check:2 ^~~
; IMPNOT-V-NEXT:check:3 ^
; IMPNOT-NEXT:>>>>>>
; IMPNOT-NOT:{{.}}
53 changes: 35 additions & 18 deletions llvm/utils/FileCheck/FileCheck.cpp
Expand Up @@ -193,14 +193,15 @@ static void DumpInputAnnotationHelp(raw_ostream &OS) {
// Labels for annotation lines.
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
OS << " labels the only match result for a pattern of type T from "
<< "line L of\n"
<< " the check file\n";
OS << " labels the only match result for either (1) a pattern of type T"
<< " from\n"
<< " line L of the check file if L is an integer or (2) the"
<< " I-th implicit\n"
<< " pattern if L is \"imp\" followed by an integer "
<< "I (index origin one)\n";
OS << " - ";
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
OS << " labels the Nth match result for a pattern of type T from line "
<< "L of\n"
<< " the check file\n";
OS << " labels the Nth match result for such a pattern\n";

// Markers on annotation lines.
OS << " - ";
Expand Down Expand Up @@ -293,9 +294,12 @@ std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
llvm_unreachable("unknown FileCheckType");
}

static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
std::vector<InputAnnotation> &Annotations,
unsigned &LabelWidth) {
static void
BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
const std::vector<FileCheckDiag> &Diags,
std::vector<InputAnnotation> &Annotations,
unsigned &LabelWidth) {
// How many diagnostics has the current check seen so far?
unsigned CheckDiagCount = 0;
// What's the widest label?
Expand All @@ -305,14 +309,24 @@ static void BuildInputAnnotations(const std::vector<FileCheckDiag> &Diags,
InputAnnotation A;

// Build label, which uniquely identifies this check result.
A.CheckLine = DiagItr->CheckLine;
unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
auto CheckLineAndCol =
SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID);
A.CheckLine = CheckLineAndCol.first;
llvm::raw_string_ostream Label(A.Label);
Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":"
<< DiagItr->CheckLine;
Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":";
if (CheckBufferID == CheckFileBufferID)
Label << CheckLineAndCol.first;
else if (ImpPatBufferIDRange.first <= CheckBufferID &&
CheckBufferID < ImpPatBufferIDRange.second)
Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
else
llvm_unreachable("expected diagnostic's check location to be either in "
"the check file or for an implicit pattern");
A.CheckDiagIndex = UINT_MAX;
auto DiagNext = std::next(DiagItr);
if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
DiagItr->CheckLine == DiagNext->CheckLine)
DiagItr->CheckLoc == DiagNext->CheckLoc)
A.CheckDiagIndex = CheckDiagCount++;
else if (CheckDiagCount) {
A.CheckDiagIndex = CheckDiagCount;
Expand Down Expand Up @@ -606,11 +620,13 @@ int main(int argc, char **argv) {
SmallString<4096> CheckFileBuffer;
StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);

SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
CheckFileText, CheckFile.getBufferIdentifier()),
SMLoc());
unsigned CheckFileBufferID =
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
CheckFileText, CheckFile.getBufferIdentifier()),
SMLoc());

if (FC.readCheckFile(SM, CheckFileText, PrefixRE))
std::pair<unsigned, unsigned> ImpPatBufferIDRange;
if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
return 2;

// Open the file to check and add it to SourceMgr.
Expand Down Expand Up @@ -658,7 +674,8 @@ int main(int argc, char **argv) {
<< "\n";
std::vector<InputAnnotation> Annotations;
unsigned LabelWidth;
BuildInputAnnotations(Diags, Annotations, LabelWidth);
BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
Annotations, LabelWidth);
DumpAnnotatedInput(errs(), Req, InputFileText, Annotations, LabelWidth);
}

Expand Down

0 comments on commit b5a2461

Please sign in to comment.