From: Duncan P. N. Exon Smith Date: Thu, 26 Feb 2015 04:53:00 +0000 (+0000) Subject: FileCheck: Add CHECK-SAME X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=9379c3152099726edc7d9aad7538c8a8ea0b736b FileCheck: Add CHECK-SAME Add `CHECK-SAME`, which requires that the pattern matches on the *same* line as the previous `CHECK`/`CHECK-NEXT` -- in other words, no newline is allowed in the skipped region. This is similar to `CHECK-NEXT`, which requires exactly 1 newline in the skipped region. My motivation is to simplify checking the long lines of LLVM assembly for the new debug info hierarchy. This allows CHECK sequences like the following: CHECK: ![[REF]] = !SomeMDNode( CHECK-SAME: file: ![[FILE:[0-9]+]] CHECK-SAME: otherField: 93{{[,)]}} which is equivalent to: CHECK: ![[REF]] = !SomeMDNode({{.*}}file: ![[FILE:[0-9]+]]{{.*}}otherField: 93{{[,)]}} While this example just has two fields, many nodes in debug info have more than that. `CHECK-SAME` will keep the logic easy to follow. Morever, it enables interleaving `CHECK-NOT`s without allowing newlines. Consider the following: CHECK: ![[REF]] = !SomeMDNode( CHECK-SAME: file: ![[FILE:[0-9]+]] CHECK-NOT: unexpectedField: CHECK-SAME: otherField: 93{{[,)]}} CHECK-NOT: otherUnexpectedField: CHECK-SAME: ) which doesn't seem to have an equivalent `CHECK` line. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230612 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/test/FileCheck/same.txt b/test/FileCheck/same.txt new file mode 100644 index 00000000000..7160936c466 --- /dev/null +++ b/test/FileCheck/same.txt @@ -0,0 +1,23 @@ +foo bat bar +baz + +RUN: FileCheck --input-file=%s --check-prefix=PASS1 %s +PASS1: foo +PASS1-SAME: bat +PASS1-SAME: bar +PASS1-NEXT: baz + +RUN: FileCheck --input-file=%s --check-prefix=PASS2 %s +PASS2: foo +PASS2-NOT: baz +PASS2-SAME: bar +PASS2-NEXT: baz + +RUN: not FileCheck --input-file=%s --check-prefix=FAIL1 %s +FAIL1: foo +FAIL1-SAME: baz + +RUN: not FileCheck --input-file=%s --check-prefix=FAIL2 %s +FAIL2: foo +FAIL2-NOT: bat +FAIL2-SAME: bar diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 59affa1ada1..146b5121ac5 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -73,6 +73,7 @@ namespace Check { CheckNone = 0, CheckPlain, CheckNext, + CheckSame, CheckNot, CheckDAG, CheckLabel, @@ -620,6 +621,9 @@ struct CheckString { /// CheckNext - Verify there is a single line in the given buffer. bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; + /// CheckSame - Verify there is no newline in the given buffer. + bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; + /// CheckNot - Verify there's no "not strings" in the given buffer. bool CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector &NotStrings, @@ -683,6 +687,9 @@ static size_t CheckTypeSize(Check::CheckType Ty) { case Check::CheckNext: return sizeof("-NEXT:") - 1; + case Check::CheckSame: + return sizeof("-SAME:") - 1; + case Check::CheckNot: return sizeof("-NOT:") - 1; @@ -713,6 +720,9 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { if (Rest.startswith("NEXT:")) return Check::CheckNext; + if (Rest.startswith("SAME:")) + return Check::CheckSame; + if (Rest.startswith("NOT:")) return Check::CheckNot; @@ -919,10 +929,12 @@ static bool ReadCheckFile(SourceMgr &SM, Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { + if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) && + CheckStrings.empty()) { + StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '" + UsedPrefix + "-NEXT:' without previous '" + "found '" + UsedPrefix + "-" + Type + "' without previous '" + UsedPrefix + ": line"); return true; } @@ -1053,6 +1065,11 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, if (CheckNext(SM, SkippedRegion)) return StringRef::npos; + // If this check is a "CHECK-SAME", verify that the previous match was on + // the same line (i.e. that there is no newline between them). + if (CheckSame(SM, SkippedRegion)) + return StringRef::npos; + // If this match had "not strings", verify that they don't exist in the // skipped region. if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable)) @@ -1101,6 +1118,34 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { return false; } +bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { + if (CheckTy != Check::CheckSame) + return false; + + // Count the number of newlines between the previous match and this one. + assert(Buffer.data() != + SM.getMemoryBuffer(SM.FindBufferContainingLoc( + SMLoc::getFromPointer(Buffer.data()))) + ->getBufferStart() && + "CHECK-SAME can't be the first check in a file"); + + const char *FirstNewLine = nullptr; + unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); + + if (NumNewLines != 0) { + SM.PrintMessage(Loc, SourceMgr::DK_Error, + Prefix + + "-SAME: is not on the same line as the previous match"); + SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, + "'next' match was here"); + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, + "previous match ended here"); + return true; + } + + return false; +} + bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector &NotStrings, StringMap &VariableTable) const {