Index: docs/CommandGuide/FileCheck.rst =================================================================== --- docs/CommandGuide/FileCheck.rst +++ docs/CommandGuide/FileCheck.rst @@ -81,6 +81,11 @@ Show the version number of this program. +.. option:: --check-word + + Adds condition for successful matching:string described in check-line should be + a separate word, but not a part of another word. + EXIT STATUS ----------- @@ -169,6 +174,24 @@ In this case, we're testing that we get the expected code generation with both 32-bit and 64-bit code generation. +The FileCheck -check-word option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want find some strings in file, but you want to be sure, that these +strings should be separate words, but not a part of other words you should +use :option:`-check-word` option. + +For example + +.. code-block:: llvm + + // RUN: FileCheck -input-file %s %s -check-word + + reg + // CHECK-WORD: {{[a-z]+}} + +This check will match with reg, but not with reg12. + The "CHECK-NEXT:" directive ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Index: test/FileCheck/check-word.txt =================================================================== --- /dev/null +++ test/FileCheck/check-word.txt @@ -0,0 +1,32 @@ +// RUN: FileCheck -input-file %s %s -check-word +// RUN: not FileCheck -input-file %s %s -check-prefix=FAILTEST -check-word + +first +and +// FAILTEST: first +// FAILTEST-SAME: and + +op1; +op2; +op33; +// CHECK: op{{[0-9]}}; +// CHECK-NEXT: op{{[0-9]}}; +// CHECK-NOT: op{{[0-9]}} + +first and +// CHECK: first +// CHECK-SAME: and +This is second line +// CHECK: second + +one two three +// CHECK-DAG: two +// CHECK-DAG: three +// CHECK-DAG: one + +four! +// CHECK: four +dog +line +// CHECK-NOT: cat +// CHECK: line Index: utils/FileCheck/FileCheck.cpp =================================================================== --- utils/FileCheck/FileCheck.cpp +++ utils/FileCheck/FileCheck.cpp @@ -73,6 +73,12 @@ "Allows leading and trailing whitespace if --strict-whitespace\n" "is not also passed.")); +static cl::opt CheckWordMode( + "check-word", cl::init(false), + cl::desc("Adds condition for successful matching:\n" + "string described in check-line should be a separate word,\n" + "but not a part of another word.")); + typedef cl::list::const_iterator prefix_iterator; //===----------------------------------------------------------------------===// @@ -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 @@ -1090,6 +1099,10 @@ if (!IsLabelScanMode) { StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos); + // If this check is a "CHECK-WORD", verify the bounds of string. + if (CheckWord(LastPos + MatchPos, MatchLen, Buffer)) + return StringRef::npos; + // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). if (CheckNext(SM, SkippedRegion)) @@ -1102,13 +1115,34 @@ // If this match had "not strings", verify that they don't exist in the // skipped region. - if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable)) + if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable) && !CheckWordMode) return StringRef::npos; } return LastPos + MatchPos; } +bool CheckString::CheckWord(const size_t &MatchPos, const size_t MatchLen, + StringRef Buffer) const { + bool isWord = true; + if (!CheckWordMode) + 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::CheckNot && isWord) || + (Pat.getCheckTy() != Check::CheckNot && !isWord); +} + bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { if (Pat.getCheckTy() != Check::CheckNext) return false;