diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst --- a/llvm/docs/CommandGuide/FileCheck.rst +++ b/llvm/docs/CommandGuide/FileCheck.rst @@ -660,6 +660,19 @@ ``CHECK-LABEL:`` directives cannot contain variable definitions or uses. +The "CHECK-LITERAL(-x):" directive +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to check a literal string match. There are no regex matching, +variable capture or expansion performed. This is useful when the text to match +would require excessive escapping otherwise. LITERAL can be used with plain +CHECK, next CHECK (CHECK-LITERAL-NEXT), COUNT, DAG, SAME, NOT or DAG CHECK (CHECK-LITERAL-DAG). + +.. code-block:: text + + %x = const [[[10]]] + ; CHECK-LITERAL: [[[10]]] + FileCheck Regex Matching Syntax ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/llvm/include/llvm/FileCheck/FileCheck.h b/llvm/include/llvm/FileCheck/FileCheck.h --- a/llvm/include/llvm/FileCheck/FileCheck.h +++ b/llvm/include/llvm/FileCheck/FileCheck.h @@ -67,9 +67,11 @@ class FileCheckType { FileCheckKind Kind; int Count; ///< optional Count for some checks + bool Literal; ///< optional Whether to treat match as literal public: - FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {} + FileCheckType(FileCheckKind Kind = CheckNone) + : Kind(Kind), Count(1), Literal(false) {} FileCheckType(const FileCheckType &) = default; FileCheckType &operator=(const FileCheckType &) = default; @@ -78,6 +80,9 @@ int getCount() const { return Count; } FileCheckType &setCount(int C); + bool isLiteralMatch() const { return Literal; } + FileCheckType &setLiteralMatch(bool literal = true); + // \returns a description of \p Prefix. std::string getDescription(StringRef Prefix) const; }; diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -917,6 +917,12 @@ return false; } + // If literal check, set fixed string. + if (CheckTy.isLiteralMatch()) { + FixedStr = PatternStr; + return false; + } + // Check to see if this is a fixed string, or if it has regex pieces. if (!MatchFullLinesHere && (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && @@ -1588,26 +1594,36 @@ return *this; } +Check::FileCheckType &Check::FileCheckType::setLiteralMatch(bool literal) { + Literal = literal; + return *this; +} + std::string Check::FileCheckType::getDescription(StringRef Prefix) const { + // Prefix the given string with Prefix & '-LITERAL' if literal match. + auto prefixed = [this, Prefix](const std::string &str) -> std::string { + return formatv("{0}{1}{2}", Prefix, Literal ? "-LITERAL" : "", str); + }; + switch (Kind) { case Check::CheckNone: return "invalid"; case Check::CheckPlain: if (Count > 1) - return Prefix.str() + "-COUNT"; - return std::string(Prefix); + return prefixed("-COUNT"); + return prefixed(""); case Check::CheckNext: - return Prefix.str() + "-NEXT"; + return prefixed("-NEXT"); case Check::CheckSame: - return Prefix.str() + "-SAME"; + return prefixed("-SAME"); case Check::CheckNot: - return Prefix.str() + "-NOT"; + return prefixed("-NOT"); case Check::CheckDAG: - return Prefix.str() + "-DAG"; + return prefixed("-DAG"); case Check::CheckLabel: - return Prefix.str() + "-LABEL"; + return prefixed("-LABEL"); case Check::CheckEmpty: - return Prefix.str() + "-EMPTY"; + return prefixed("-EMPTY"); case Check::CheckComment: return std::string(Prefix); case Check::CheckEOF: @@ -1637,9 +1653,14 @@ return {Check::CheckNone, StringRef()}; } + bool Literal = Rest.consume_front("LITERAL"); + if (Literal) + NextChar = Rest.front(); + // Verify that the : is present after the prefix. if (NextChar == ':') - return {Check::CheckPlain, Rest}; + return {Check::FileCheckType(Check::CheckPlain).setLiteralMatch(Literal), + Rest}; if (NextChar != '-') return {Check::CheckNone, StringRef()}; @@ -1653,23 +1674,31 @@ return {Check::CheckBadCount, Rest}; if (!Rest.consume_front(":")) return {Check::CheckBadCount, Rest}; - return {Check::FileCheckType(Check::CheckPlain).setCount(Count), Rest}; + return {Check::FileCheckType(Check::CheckPlain) + .setCount(Count) + .setLiteralMatch(Literal), + Rest}; } if (Rest.consume_front("NEXT:")) - return {Check::CheckNext, Rest}; + return {Check::FileCheckType(Check::CheckNext).setLiteralMatch(Literal), + Rest}; if (Rest.consume_front("SAME:")) - return {Check::CheckSame, Rest}; + return {Check::FileCheckType(Check::CheckSame).setLiteralMatch(Literal), + Rest}; if (Rest.consume_front("NOT:")) - return {Check::CheckNot, Rest}; + return {Check::FileCheckType(Check::CheckNot).setLiteralMatch(Literal), + Rest}; if (Rest.consume_front("DAG:")) - return {Check::CheckDAG, Rest}; + return {Check::FileCheckType(Check::CheckDAG).setLiteralMatch(Literal), + Rest}; if (Rest.consume_front("LABEL:")) - return {Check::CheckLabel, Rest}; + return {Check::FileCheckType(Check::CheckLabel).setLiteralMatch(Literal), + Rest}; if (Rest.consume_front("EMPTY:")) return {Check::CheckEmpty, Rest}; diff --git a/llvm/test/FileCheck/check-literal.txt b/llvm/test/FileCheck/check-literal.txt new file mode 100644 --- /dev/null +++ b/llvm/test/FileCheck/check-literal.txt @@ -0,0 +1,8 @@ +; RUN: FileCheck -check-prefix=A -input-file %s %s + +The result is "[[[5371]], [[5372]], [[5373]], [[5374]]]" +{{there you go.*}} + +; A-LITERAL: [[[5371]], [[5372]], +; A-LITERAL-SAME: [[5374]], [[5374]]] +; A-LITERAL-NEXT: {{there you go.*}}