Index: test/FileCheck/check-word.txt =================================================================== --- /dev/null +++ test/FileCheck/check-word.txt @@ -0,0 +1,26 @@ +// RUN: FileCheck -input-file %s %s + +op1; +op2; +op33; +// CHECK-WORD: op{{[0-9]}}; +// CHECk-WORD-NEXT: op{{[0-9]}}; +// CHECk-WORD-NOT: op{{[0-9]}} + +first and +// CHECK-WORD: first +// CHECK-WORD-SAME: and +This is second line +// CHECK-WORD: second + +one two three +// CHECK-WORD-DAG: two +// CHECK-WORD-DAG: three +// CHECK-WORD-DAG: one + +four! +// CHECK-WORD: four +dog +line +// CHECK-WORD-NOT: cat +// CHECK: line \ No newline at end of file Index: utils/FileCheck/FileCheck.cpp =================================================================== --- utils/FileCheck/FileCheck.cpp +++ utils/FileCheck/FileCheck.cpp @@ -88,6 +88,11 @@ CheckNot, CheckDAG, CheckLabel, + CheckWord, + CheckWordNext, + CheckWordSame, + CheckWordNot, + CheckWordDAG, /// MatchEOF - When set, this pattern only matches the end of file. This is /// used for trailing CHECK-NOTs. @@ -187,7 +192,8 @@ StringRef Prefix, SourceMgr &SM, unsigned LineNumber) { - bool MatchFullLinesHere = MatchFullLines && CheckTy != Check::CheckNot; + bool MatchFullLinesHere = MatchFullLines && CheckTy != Check::CheckNot && + CheckTy != Check::CheckWordNot; this->LineNumber = LineNumber; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); @@ -654,6 +660,9 @@ size_t CheckDag(const SourceMgr &SM, StringRef Buffer, std::vector &NotStrings, StringMap &VariableTable) const; + + /// CheckWord - Verify there is a single word. + bool CheckWord(const size_t &MatchPos, const size_t &MatchLen, StringRef Buffer) const; }; /// Canonicalize whitespaces in the input file. Line endings are replaced @@ -721,6 +730,21 @@ case Check::CheckLabel: return sizeof("-LABEL:") - 1; + case Check::CheckWord: + return sizeof("-WORD:") - 1; + + case Check::CheckWordNext: + return sizeof("-WORD-NEXT:") - 1; + + case Check::CheckWordSame: + return sizeof("-WORD-SAME:") - 1; + + case Check::CheckWordNot: + return sizeof("-WORD-NOT:") - 1; + + case Check::CheckWordDAG: + return sizeof("-WORD-DAG:") - 1; + case Check::CheckEOF: llvm_unreachable("Should not be using EOF size"); } @@ -754,6 +778,21 @@ if (Rest.startswith("LABEL:")) return Check::CheckLabel; + if (Rest.startswith("WORD:")) + return Check::CheckWord; + + if (Rest.startswith("WORD-NEXT:")) + return Check::CheckWordNext; + + if (Rest.startswith("WORD-SAME:")) + return Check::CheckWordSame; + + if (Rest.startswith("WORD-NOT:")) + return Check::CheckWordNot; + + if (Rest.startswith("WORD-DAG:")) + return Check::CheckWordDAG; + // You can't combine -NOT with another suffix. if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") || Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") || @@ -963,9 +1002,10 @@ Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) && + if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame || + CheckTy == Check::CheckWordNext || CheckTy == Check::CheckWordSame) && CheckStrings.empty()) { - StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; + StringRef Type = CheckTy == Check::CheckNext || Check::CheckWordNext ? "NEXT" : "SAME"; SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-" + Type + "' without previous '" @@ -974,7 +1014,8 @@ } // Handle CHECK-DAG/-NOT. - if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { + if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot || + CheckTy == Check::CheckWordDAG || CheckTy == Check::CheckWordNot) { DagNotMatches.push_back(P); continue; } @@ -1104,13 +1145,37 @@ // skipped region. if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable)) return StringRef::npos; + + //if this check is a "CHECK-WORD", verify the bounds of string. + if (CheckWord(LastPos + MatchPos, MatchLen, Buffer)) + return StringRef::npos; } return LastPos + MatchPos; } +bool CheckString::CheckWord(const size_t &MatchPos, const size_t &MatchLen, StringRef Buffer) const { + bool isWord = true; + if (Pat.getCheckTy() != Check::CheckWord && Pat.getCheckTy() != Check::CheckWordNext && + Pat.getCheckTy() != Check::CheckWordSame && Pat.getCheckTy() != Check::CheckWordDAG && + Pat.getCheckTy() != Check::CheckWordNot) + return false; + // Check previous and next characters to understand word or not. + if (MatchPos != 0) { + if (!isspace(Buffer[MatchPos - 1]) && !ispunct(Buffer[MatchPos - 1])) { + isWord = false; + } + } + if (MatchPos + MatchLen < Buffer.size() && + !isspace(Buffer[MatchPos + MatchLen ]) && !ispunct(Buffer[MatchPos + MatchLen])) { + isWord = false; + } + return (Pat.getCheckTy() == Check::CheckWordNot && isWord) || + (Pat.getCheckTy() != Check::CheckWordNot && !isWord); +} + bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { - if (Pat.getCheckTy() != Check::CheckNext) + if (Pat.getCheckTy() != Check::CheckNext && Pat.getCheckTy() != Check::CheckWordNext) return false; // Count the number of newlines between the previous match and this one. @@ -1149,7 +1214,7 @@ } bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { - if (Pat.getCheckTy() != Check::CheckSame) + if (Pat.getCheckTy() != Check::CheckSame && Pat.getCheckTy() != Check::CheckWordSame) return false; // Count the number of newlines between the previous match and this one. @@ -1180,7 +1245,8 @@ const std::vector &NotStrings, StringMap &VariableTable) const { for (const Pattern *Pat : NotStrings) { - assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); + assert((Pat->getCheckTy() == Check::CheckNot || Pat->getCheckTy() == Check::CheckWordNot) && + "Expect CHECK-NOT!"); size_t MatchLen = 0; size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); @@ -1209,15 +1275,18 @@ for (const Pattern &Pat : DagNotStrings) { assert((Pat.getCheckTy() == Check::CheckDAG || - Pat.getCheckTy() == Check::CheckNot) && + Pat.getCheckTy() == Check::CheckNot || + Pat.getCheckTy() == Check::CheckWordDAG || + Pat.getCheckTy() == Check::CheckWordNot) && "Invalid CHECK-DAG or CHECK-NOT!"); - if (Pat.getCheckTy() == Check::CheckNot) { + if (Pat.getCheckTy() == Check::CheckNot || Pat.getCheckTy() == Check::CheckWordNot) { NotStrings.push_back(&Pat); continue; } - assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!"); + assert((Pat.getCheckTy() == Check::CheckDAG || Pat.getCheckTy() == Check::CheckWordDAG) && + "Expect CHECK-DAG!"); size_t MatchLen = 0, MatchPos;