[FileCheck] Implement --ignore-case option.

The FileCheck utility is enhanced to support a `--ignore-case`
option. This is useful in cases where the output of Unix tools
differs in case (e.g. case not specified by Posix).

Reviewers: Bigcheese, jakehehrlich, rupprecht, espindola, alexshap, jhenderson, MaskRay

Differential Revision: https://reviews.llvm.org/D68146

llvm-svn: 374339
This commit is contained in:
Kai Nacke 2019-10-10 13:15:41 +00:00
parent a3ca7acb4f
commit dfd2b6f07f
6 changed files with 4202 additions and 4138 deletions

View File

@ -71,6 +71,11 @@ and from the command line.
The :option:`--strict-whitespace` argument disables this behavior. End-of-line The :option:`--strict-whitespace` argument disables this behavior. End-of-line
sequences are canonicalized to UNIX-style ``\n`` in all modes. 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 .. option:: --implicit-check-not check-pattern
Adds implicit negative checks for the specified patterns between positive Adds implicit negative checks for the specified patterns between positive

View File

@ -30,6 +30,7 @@ struct FileCheckRequest {
std::vector<std::string> GlobalDefines; std::vector<std::string> GlobalDefines;
bool AllowEmptyInput = false; bool AllowEmptyInput = false;
bool MatchFullLines = false; bool MatchFullLines = false;
bool IgnoreCase = false;
bool EnableVarScope = false; bool EnableVarScope = false;
bool AllowDeprecatedDagOverlap = false; bool AllowDeprecatedDagOverlap = false;
bool Verbose = false; bool Verbose = false;

View File

@ -320,6 +320,7 @@ bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
SourceMgr &SM, SourceMgr &SM,
const FileCheckRequest &Req) { const FileCheckRequest &Req) {
bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
IgnoreCase = Req.IgnoreCase;
PatternLoc = SMLoc::getFromPointer(PatternStr.data()); PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@ -619,7 +620,8 @@ Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
// If this is a fixed string pattern, just match it now. // If this is a fixed string pattern, just match it now.
if (!FixedStr.empty()) { if (!FixedStr.empty()) {
MatchLen = FixedStr.size(); MatchLen = FixedStr.size();
size_t Pos = Buffer.find(FixedStr); size_t Pos = IgnoreCase ? Buffer.find_lower(FixedStr)
: Buffer.find(FixedStr);
if (Pos == StringRef::npos) if (Pos == StringRef::npos)
return make_error<FileCheckNotFoundError>(); return make_error<FileCheckNotFoundError>();
return Pos; return Pos;
@ -657,7 +659,10 @@ Expected<size_t> FileCheckPattern::match(StringRef Buffer, size_t &MatchLen,
} }
SmallVector<StringRef, 4> MatchInfo; SmallVector<StringRef, 4> 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<FileCheckNotFoundError>(); return make_error<FileCheckNotFoundError>();
// Successful regex match. // Successful regex match.

View File

@ -428,6 +428,9 @@ class FileCheckPattern {
/// line to the one with this CHECK. /// line to the one with this CHECK.
Optional<size_t> LineNumber; Optional<size_t> LineNumber;
/// Ignore case while matching if set to true.
bool IgnoreCase = false;
public: public:
FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context, FileCheckPattern(Check::FileCheckType Ty, FileCheckPatternContext *Context,
Optional<size_t> Line = None) Optional<size_t> Line = None)

View File

@ -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

View File

@ -48,6 +48,10 @@ static cl::opt<bool> NoCanonicalizeWhiteSpace(
"strict-whitespace", "strict-whitespace",
cl::desc("Do not treat all horizontal whitespace as equivalent")); cl::desc("Do not treat all horizontal whitespace as equivalent"));
static cl::opt<bool> IgnoreCase(
"ignore-case",
cl::desc("Use case-insensitive matching"));
static cl::list<std::string> ImplicitCheckNot( static cl::list<std::string> ImplicitCheckNot(
"implicit-check-not", "implicit-check-not",
cl::desc("Add an implicit negative check with this pattern to every\n" 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.VerboseVerbose = VerboseVerbose;
Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace; Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
Req.MatchFullLines = MatchFullLines; Req.MatchFullLines = MatchFullLines;
Req.IgnoreCase = IgnoreCase;
if (VerboseVerbose) if (VerboseVerbose)
Req.Verbose = true; Req.Verbose = true;