[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

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +1,181 @@
//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==// //==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//
// //
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information. // See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
/// \file This file has some utilities to use FileCheck as an API /// \file This file has some utilities to use FileCheck as an API
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_FILECHECK_H #ifndef LLVM_SUPPORT_FILECHECK_H
#define LLVM_SUPPORT_FILECHECK_H #define LLVM_SUPPORT_FILECHECK_H
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h" #include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SourceMgr.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace llvm { namespace llvm {
/// Contains info about various FileCheck options. /// Contains info about various FileCheck options.
struct FileCheckRequest { struct FileCheckRequest {
std::vector<std::string> CheckPrefixes; std::vector<std::string> CheckPrefixes;
bool NoCanonicalizeWhiteSpace = false; bool NoCanonicalizeWhiteSpace = false;
std::vector<std::string> ImplicitCheckNot; std::vector<std::string> ImplicitCheckNot;
std::vector<std::string> GlobalDefines; std::vector<std::string> GlobalDefines;
bool AllowEmptyInput = false; bool AllowEmptyInput = false;
bool MatchFullLines = false; bool MatchFullLines = false;
bool EnableVarScope = false; bool IgnoreCase = false;
bool AllowDeprecatedDagOverlap = false; bool EnableVarScope = false;
bool Verbose = false; bool AllowDeprecatedDagOverlap = false;
bool VerboseVerbose = false; bool Verbose = false;
}; bool VerboseVerbose = false;
};
//===----------------------------------------------------------------------===//
// Summary of a FileCheck diagnostic. //===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===// // Summary of a FileCheck diagnostic.
//===----------------------------------------------------------------------===//
namespace Check {
namespace Check {
enum FileCheckKind {
CheckNone = 0, enum FileCheckKind {
CheckPlain, CheckNone = 0,
CheckNext, CheckPlain,
CheckSame, CheckNext,
CheckNot, CheckSame,
CheckDAG, CheckNot,
CheckLabel, CheckDAG,
CheckEmpty, CheckLabel,
CheckEmpty,
/// Indicates the pattern only matches the end of file. This is used for
/// trailing CHECK-NOTs. /// Indicates the pattern only matches the end of file. This is used for
CheckEOF, /// trailing CHECK-NOTs.
CheckEOF,
/// Marks when parsing found a -NOT check combined with another CHECK suffix.
CheckBadNot, /// Marks when parsing found a -NOT check combined with another CHECK suffix.
CheckBadNot,
/// Marks when parsing found a -COUNT directive with invalid count value.
CheckBadCount /// Marks when parsing found a -COUNT directive with invalid count value.
}; CheckBadCount
};
class FileCheckType {
FileCheckKind Kind; class FileCheckType {
int Count; ///< optional Count for some checks FileCheckKind Kind;
int Count; ///< optional Count for some checks
public:
FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {} public:
FileCheckType(const FileCheckType &) = default; FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}
FileCheckType(const FileCheckType &) = default;
operator FileCheckKind() const { return Kind; }
operator FileCheckKind() const { return Kind; }
int getCount() const { return Count; }
FileCheckType &setCount(int C); int getCount() const { return Count; }
FileCheckType &setCount(int C);
// \returns a description of \p Prefix.
std::string getDescription(StringRef Prefix) const; // \returns a description of \p Prefix.
}; std::string getDescription(StringRef Prefix) const;
} // namespace Check };
} // namespace Check
struct FileCheckDiag {
/// What is the FileCheck directive for this diagnostic? struct FileCheckDiag {
Check::FileCheckType CheckTy; /// What is the FileCheck directive for this diagnostic?
/// Where is the FileCheck directive for this diagnostic? Check::FileCheckType CheckTy;
unsigned CheckLine, CheckCol; /// Where is the FileCheck directive for this diagnostic?
/// What type of match result does this diagnostic describe? unsigned CheckLine, CheckCol;
/// /// What type of match result does this diagnostic describe?
/// A directive's supplied pattern is said to be either expected or excluded ///
/// depending on whether the pattern must have or must not have a match in /// A directive's supplied pattern is said to be either expected or excluded
/// order for the directive to succeed. For example, a CHECK directive's /// depending on whether the pattern must have or must not have a match in
/// pattern is expected, and a CHECK-NOT directive's pattern is excluded. /// order for the directive to succeed. For example, a CHECK directive's
/// All match result types whose names end with "Excluded" are for excluded /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.
/// patterns, and all others are for expected patterns. /// All match result types whose names end with "Excluded" are for excluded
/// /// patterns, and all others are for expected patterns.
/// There might be more than one match result for a single pattern. For ///
/// example, there might be several discarded matches /// There might be more than one match result for a single pattern. For
/// (MatchFoundButDiscarded) before either a good match /// example, there might be several discarded matches
/// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected), /// (MatchFoundButDiscarded) before either a good match
/// and there might be a fuzzy match (MatchFuzzy) after the latter. /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),
enum MatchType { /// and there might be a fuzzy match (MatchFuzzy) after the latter.
/// Indicates a good match for an expected pattern. enum MatchType {
MatchFoundAndExpected, /// Indicates a good match for an expected pattern.
/// Indicates a match for an excluded pattern. MatchFoundAndExpected,
MatchFoundButExcluded, /// Indicates a match for an excluded pattern.
/// Indicates a match for an expected pattern, but the match is on the MatchFoundButExcluded,
/// wrong line. /// Indicates a match for an expected pattern, but the match is on the
MatchFoundButWrongLine, /// wrong line.
/// Indicates a discarded match for an expected pattern. MatchFoundButWrongLine,
MatchFoundButDiscarded, /// Indicates a discarded match for an expected pattern.
/// Indicates no match for an excluded pattern. MatchFoundButDiscarded,
MatchNoneAndExcluded, /// Indicates no match for an excluded pattern.
/// Indicates no match for an expected pattern, but this might follow good MatchNoneAndExcluded,
/// matches when multiple matches are expected for the pattern, or it might /// Indicates no match for an expected pattern, but this might follow good
/// follow discarded matches for the pattern. /// matches when multiple matches are expected for the pattern, or it might
MatchNoneButExpected, /// follow discarded matches for the pattern.
/// Indicates a fuzzy match that serves as a suggestion for the next MatchNoneButExpected,
/// intended match for an expected pattern with too few or no good matches. /// Indicates a fuzzy match that serves as a suggestion for the next
MatchFuzzy, /// intended match for an expected pattern with too few or no good matches.
} MatchTy; MatchFuzzy,
/// The search range if MatchTy is MatchNoneAndExcluded or } MatchTy;
/// MatchNoneButExpected, or the match range otherwise. /// The search range if MatchTy is MatchNoneAndExcluded or
unsigned InputStartLine; /// MatchNoneButExpected, or the match range otherwise.
unsigned InputStartCol; unsigned InputStartLine;
unsigned InputEndLine; unsigned InputStartCol;
unsigned InputEndCol; unsigned InputEndLine;
FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy, unsigned InputEndCol;
SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange); FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
}; SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);
};
class FileCheckPatternContext;
struct FileCheckString; class FileCheckPatternContext;
struct FileCheckString;
/// FileCheck class takes the request and exposes various methods that
/// use information from the request. /// FileCheck class takes the request and exposes various methods that
class FileCheck { /// use information from the request.
FileCheckRequest Req; class FileCheck {
std::unique_ptr<FileCheckPatternContext> PatternContext; FileCheckRequest Req;
// C++17 TODO: make this a plain std::vector. std::unique_ptr<FileCheckPatternContext> PatternContext;
std::unique_ptr<std::vector<FileCheckString>> CheckStrings; // C++17 TODO: make this a plain std::vector.
std::unique_ptr<std::vector<FileCheckString>> CheckStrings;
public:
explicit FileCheck(FileCheckRequest Req); public:
~FileCheck(); explicit FileCheck(FileCheckRequest Req);
~FileCheck();
// Combines the check prefixes into a single regex so that we can efficiently
// scan for any of the set. // Combines the check prefixes into a single regex so that we can efficiently
// // scan for any of the set.
// The semantics are that the longest-match wins which matches our regex //
// library. // The semantics are that the longest-match wins which matches our regex
Regex buildCheckPrefixRegex(); // library.
Regex buildCheckPrefixRegex();
/// Reads the check file from \p Buffer and records the expected strings it
/// contains. Errors are reported against \p SM. /// Reads the check file from \p Buffer and records the expected strings it
/// /// contains. Errors are reported against \p SM.
/// Only expected strings whose prefix is one of those listed in \p PrefixRE ///
/// are recorded. \returns true in case of an error, false otherwise. /// Only expected strings whose prefix is one of those listed in \p PrefixRE
bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE); /// are recorded. \returns true in case of an error, false otherwise.
bool readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE);
bool ValidateCheckPrefixes();
bool ValidateCheckPrefixes();
/// Canonicalizes whitespaces in the file. Line endings are replaced with
/// UNIX-style '\n'. /// Canonicalizes whitespaces in the file. Line endings are replaced with
StringRef CanonicalizeFile(MemoryBuffer &MB, /// UNIX-style '\n'.
SmallVectorImpl<char> &OutputBuffer); StringRef CanonicalizeFile(MemoryBuffer &MB,
SmallVectorImpl<char> &OutputBuffer);
/// Checks the input to FileCheck provided in the \p Buffer against the
/// expected strings read from the check file and record diagnostics emitted /// Checks the input to FileCheck provided in the \p Buffer against the
/// in \p Diags. Errors are recorded against \p SM. /// expected strings read from the check file and record diagnostics emitted
/// /// in \p Diags. Errors are recorded against \p SM.
/// \returns false if the input fails to satisfy the checks. ///
bool checkInput(SourceMgr &SM, StringRef Buffer, /// \returns false if the input fails to satisfy the checks.
std::vector<FileCheckDiag> *Diags = nullptr); bool checkInput(SourceMgr &SM, StringRef Buffer,
}; std::vector<FileCheckDiag> *Diags = nullptr);
};
} // namespace llvm
} // namespace llvm
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff