diff --git a/docs/CommandGuide/FileCheck.rst b/docs/CommandGuide/FileCheck.rst index e8b324d080d..0072c9c0347 100644 --- a/docs/CommandGuide/FileCheck.rst +++ b/docs/CommandGuide/FileCheck.rst @@ -71,6 +71,11 @@ and from the command line. The :option:`--strict-whitespace` argument disables this behavior. End-of-line sequences are canonicalized to UNIX-style ``\n`` in all modes. +.. option:: --ignore-case + + By default, FileCheck uses case-sensitive matching. This option causes + FileCheck to use case-insensitive matching. + .. option:: --implicit-check-not check-pattern Adds implicit negative checks for the specified patterns between positive diff --git a/include/llvm/Support/FileCheck.h b/include/llvm/Support/FileCheck.h index 5c6585ed76f..2547449246a 100644 --- a/include/llvm/Support/FileCheck.h +++ b/include/llvm/Support/FileCheck.h @@ -30,6 +30,7 @@ struct FileCheckRequest { std::vector GlobalDefines; bool AllowEmptyInput = false; bool MatchFullLines = false; + bool IgnoreCase = false; bool EnableVarScope = false; bool AllowDeprecatedDagOverlap = false; bool Verbose = false; diff --git a/lib/Support/FileCheck.cpp b/lib/Support/FileCheck.cpp index c3f537b3524..841e406a7b6 100644 --- a/lib/Support/FileCheck.cpp +++ b/lib/Support/FileCheck.cpp @@ -320,6 +320,7 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, const FileCheckRequest &Req) { bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; + IgnoreCase = Req.IgnoreCase; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); @@ -619,7 +620,8 @@ Expected FileCheckPattern::match(StringRef Buffer, size_t &MatchLen, // If this is a fixed string pattern, just match it now. if (!FixedStr.empty()) { MatchLen = FixedStr.size(); - size_t Pos = Buffer.find(FixedStr); + size_t Pos = IgnoreCase ? Buffer.find_lower(FixedStr) + : Buffer.find(FixedStr); if (Pos == StringRef::npos) return make_error(); return Pos; @@ -657,7 +659,10 @@ Expected FileCheckPattern::match(StringRef Buffer, size_t &MatchLen, } SmallVector MatchInfo; - if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo)) + unsigned int Flags = Regex::Newline; + if (IgnoreCase) + Flags |= Regex::IgnoreCase; + if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo)) return make_error(); // Successful regex match. diff --git a/lib/Support/FileCheckImpl.h b/lib/Support/FileCheckImpl.h index 001b3589d5f..06ce8301cec 100644 --- a/lib/Support/FileCheckImpl.h +++ b/lib/Support/FileCheckImpl.h @@ -428,6 +428,9 @@ class FileCheckPattern { /// line to the one with this CHECK. Optional LineNumber; + /// Ignore case while matching if set to true. + bool IgnoreCase = false; + public: FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context, Optional Line = None) diff --git a/test/FileCheck/check-ignore-case.txt b/test/FileCheck/check-ignore-case.txt new file mode 100644 index 00000000000..6a42a52fc44 --- /dev/null +++ b/test/FileCheck/check-ignore-case.txt @@ -0,0 +1,45 @@ +## Check that a full line is matched case insensitively. +# RUN: FileCheck --ignore-case --match-full-lines --check-prefix=FULL --input-file=%s %s + +## Check that a regular expression matches case insensitively. +# RUN: FileCheck --ignore-case --check-prefix=REGEX --input-file=%s %s + +## Check that a pattern from command line matches case insensitively. +# RUN: FileCheck --ignore-case --check-prefix=PAT --DPATTERN="THIS is the" --input-file=%s %s + +## Check that COUNT and NEXT work case insensitively. +# RUN: FileCheck --ignore-case --check-prefix=CNT --input-file=%s %s + +## Check that match on same line works case insensitively. +# RUN: FileCheck --ignore-case --check-prefix=LINE --input-file=%s %s + +## Check that option --implicit-not works case insensitively. +# RUN: sed '/^#/d' %s | FileCheck --implicit-check-not=sTrInG %s +# RUN: sed '/^#/d' %s | not FileCheck --ignore-case --implicit-check-not=sTrInG %s 2>&1 | FileCheck --check-prefix=ERROR %s + +this is the STRING to be matched + +# FULL: tHis iS The String TO be matched +# REGEX: s{{TRing}} +# PAT: [[PATTERN]] string + +Loop 1 +lOop 2 +loOp 3 +looP 4 +loop 5 +LOOP 6 +BREAK + +# CNT-COUNT-6: LOop {{[0-9]}} +# CNT-NOT: loop +# CNT-NEXT: break + +One Line To Match + +# LINE: {{o}}ne line +# LINE-SAME: {{t}}o match + +# ERROR: command line:1:{{[0-9]+}}: error: CHECK-NOT: excluded string found in input +# ERROR-NEXT: -implicit-check-not='sTrInG' +# ERROR: note: found here diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 8718be28ac9..44d5be13751 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -48,6 +48,10 @@ static cl::opt NoCanonicalizeWhiteSpace( "strict-whitespace", cl::desc("Do not treat all horizontal whitespace as equivalent")); +static cl::opt IgnoreCase( + "ignore-case", + cl::desc("Use case-insensitive matching")); + static cl::list ImplicitCheckNot( "implicit-check-not", cl::desc("Add an implicit negative check with this pattern to every\n" @@ -555,6 +559,7 @@ int main(int argc, char **argv) { Req.VerboseVerbose = VerboseVerbose; Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace; Req.MatchFullLines = MatchFullLines; + Req.IgnoreCase = IgnoreCase; if (VerboseVerbose) Req.Verbose = true;