mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2026-01-31 01:35:20 +01:00
This patch implements annotations for diagnostics reporting CHECK-NOT
failed matches. These diagnostics are enabled by -vv. As for
diagnostics reporting failed matches for other directives, these
annotations mark the search ranges using `X~~`. The difference here
is that failed matches for CHECK-NOT are successes not errors, so they
are green not red when colors are enabled.
For example:
```
$ FileCheck -dump-input=help
The following description was requested by -dump-input=help to
explain the input annotations printed by -dump-input=always and
-dump-input=fail:
- L: labels line number L of the input file
- T:L labels the only match result for a pattern of type T from line L of
the check file
- T:L'N labels the Nth match result for a pattern of type T from line L of
the check file
- ^~~ marks good match (reported if -v)
- !~~ marks bad match, such as:
- CHECK-NEXT on same line as previous match (error)
- CHECK-NOT found (error)
- CHECK-DAG overlapping match (discarded, reported if -vv)
- X~~ marks search range when no match is found, such as:
- CHECK-NEXT not found (error)
- CHECK-NOT not found (success, reported if -vv)
- CHECK-DAG not found after discarded matches (error)
- ? marks fuzzy match when no match is found
- colors success, error, fuzzy match, discarded match, unmatched input
If you are not seeing color above or in input dumps, try: -color
$ FileCheck -vv -dump-input=always check5 < input5 |& sed -n '/^<<<</,$p'
<<<<<<
1: abcdef
check:1 ^~~
not:2 X~~
2: ghijkl
not:2 ~~~
check:3 ^~~
3: mnopqr
not:4 X~~~~~
4: stuvwx
not:4 ~~~~~~
5:
eof:4 ^
>>>>>>
$ cat check5
CHECK: abc
CHECK-NOT: foobar
CHECK: jkl
CHECK-NOT: foobar
$ cat input5
abcdef
ghijkl
mnopqr
stuvwx
```
Reviewed By: george.karpenkov, probinson
Differential Revision: https://reviews.llvm.org/D53899
llvm-svn: 349424
269 lines
9.3 KiB
C++
269 lines
9.3 KiB
C++
//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file This file has some utilities to use FileCheck as an API
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_SUPPORT_FILECHECK_H
|
|
#define LLVM_SUPPORT_FILECHECK_H
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Regex.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
namespace llvm {
|
|
|
|
/// Contains info about various FileCheck options.
|
|
struct FileCheckRequest {
|
|
std::vector<std::string> CheckPrefixes;
|
|
bool NoCanonicalizeWhiteSpace = false;
|
|
std::vector<std::string> ImplicitCheckNot;
|
|
std::vector<std::string> GlobalDefines;
|
|
bool AllowEmptyInput = false;
|
|
bool MatchFullLines = false;
|
|
bool EnableVarScope = false;
|
|
bool AllowDeprecatedDagOverlap = false;
|
|
bool Verbose = false;
|
|
bool VerboseVerbose = false;
|
|
};
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Pattern Handling Code.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace Check {
|
|
|
|
enum FileCheckKind {
|
|
CheckNone = 0,
|
|
CheckPlain,
|
|
CheckNext,
|
|
CheckSame,
|
|
CheckNot,
|
|
CheckDAG,
|
|
CheckLabel,
|
|
CheckEmpty,
|
|
|
|
/// Indicates the pattern only matches the end of file. This is used for
|
|
/// trailing CHECK-NOTs.
|
|
CheckEOF,
|
|
|
|
/// 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
|
|
};
|
|
|
|
class FileCheckType {
|
|
FileCheckKind Kind;
|
|
int Count; ///< optional Count for some checks
|
|
|
|
public:
|
|
FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}
|
|
FileCheckType(const FileCheckType &) = default;
|
|
|
|
operator FileCheckKind() const { return Kind; }
|
|
|
|
int getCount() const { return Count; }
|
|
FileCheckType &setCount(int C);
|
|
|
|
std::string getDescription(StringRef Prefix) const;
|
|
};
|
|
}
|
|
|
|
struct FileCheckDiag;
|
|
|
|
class FileCheckPattern {
|
|
SMLoc PatternLoc;
|
|
|
|
/// A fixed string to match as the pattern or empty if this pattern requires
|
|
/// a regex match.
|
|
StringRef FixedStr;
|
|
|
|
/// A regex string to match as the pattern or empty if this pattern requires
|
|
/// a fixed string to match.
|
|
std::string RegExStr;
|
|
|
|
/// Entries in this vector map to uses of a variable in the pattern, e.g.
|
|
/// "foo[[bar]]baz". In this case, the RegExStr will contain "foobaz" and
|
|
/// we'll get an entry in this vector that tells us to insert the value of
|
|
/// bar at offset 3.
|
|
std::vector<std::pair<StringRef, unsigned>> VariableUses;
|
|
|
|
/// Maps definitions of variables to their parenthesized capture numbers.
|
|
///
|
|
/// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to
|
|
/// 1.
|
|
std::map<StringRef, unsigned> VariableDefs;
|
|
|
|
Check::FileCheckType CheckTy;
|
|
|
|
/// Contains the number of line this pattern is in.
|
|
unsigned LineNumber;
|
|
|
|
public:
|
|
explicit FileCheckPattern(Check::FileCheckType Ty)
|
|
: CheckTy(Ty) {}
|
|
|
|
/// Returns the location in source code.
|
|
SMLoc getLoc() const { return PatternLoc; }
|
|
|
|
bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
|
|
unsigned LineNumber, const FileCheckRequest &Req);
|
|
size_t Match(StringRef Buffer, size_t &MatchLen,
|
|
StringMap<StringRef> &VariableTable) const;
|
|
void PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
|
|
const StringMap<StringRef> &VariableTable,
|
|
SMRange MatchRange = None) const;
|
|
void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
|
|
const StringMap<StringRef> &VariableTable,
|
|
std::vector<FileCheckDiag> *Diags) const;
|
|
|
|
bool hasVariable() const {
|
|
return !(VariableUses.empty() && VariableDefs.empty());
|
|
}
|
|
|
|
Check::FileCheckType getCheckTy() const { return CheckTy; }
|
|
|
|
int getCount() const { return CheckTy.getCount(); }
|
|
|
|
private:
|
|
bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
|
|
void AddBackrefToRegEx(unsigned BackrefNum);
|
|
unsigned
|
|
ComputeMatchDistance(StringRef Buffer,
|
|
const StringMap<StringRef> &VariableTable) const;
|
|
bool EvaluateExpression(StringRef Expr, std::string &Value) const;
|
|
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// Summary of a FileCheck diagnostic.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct FileCheckDiag {
|
|
/// What is the FileCheck directive for this diagnostic?
|
|
Check::FileCheckType CheckTy;
|
|
/// Where is the FileCheck directive for this diagnostic?
|
|
unsigned CheckLine, CheckCol;
|
|
/// What kind of match result does this diagnostic describe?
|
|
///
|
|
/// There might be more than one of these for the same directive. For
|
|
/// example, there might be several discards before either a final or fail,
|
|
/// and there might be a fuzzy match after a fail.
|
|
enum MatchType {
|
|
// TODO: More members will appear with later patches in this series.
|
|
/// Indicates the final match for an expected pattern.
|
|
MatchFinalAndExpected,
|
|
/// Indicates the final match for an excluded pattern.
|
|
MatchFinalButExcluded,
|
|
/// Indicates the final match for an expected pattern, but the match is on
|
|
/// the wrong line.
|
|
MatchFinalButWrongLine,
|
|
/// Indicates a discarded match for an expected pattern.
|
|
MatchDiscard,
|
|
/// Indicates no match for an excluded pattern.
|
|
MatchNoneAndExcluded,
|
|
/// Indicates no match for an expected pattern.
|
|
MatchNoneButExpected,
|
|
/// Indicates a possible intended match because there's no perfect match.
|
|
MatchFuzzy,
|
|
} MatchTy;
|
|
/// The match range if MatchTy is not MatchNoneAndExcluded or
|
|
/// MatchNoneButExpected, or the search range otherwise.
|
|
unsigned InputStartLine, InputStartCol, InputEndLine, InputEndCol;
|
|
FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
|
|
SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Check Strings.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A check that we found in the input file.
|
|
struct FileCheckString {
|
|
/// The pattern to match.
|
|
FileCheckPattern Pat;
|
|
|
|
/// Which prefix name this check matched.
|
|
StringRef Prefix;
|
|
|
|
/// The location in the match file that the check string was specified.
|
|
SMLoc Loc;
|
|
|
|
/// All of the strings that are disallowed from occurring between this match
|
|
/// string and the previous one (or start of file).
|
|
std::vector<FileCheckPattern> DagNotStrings;
|
|
|
|
FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)
|
|
: Pat(P), Prefix(S), Loc(L) {}
|
|
|
|
size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
|
|
size_t &MatchLen, StringMap<StringRef> &VariableTable,
|
|
FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const;
|
|
|
|
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
|
|
bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
|
|
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
|
|
const std::vector<const FileCheckPattern *> &NotStrings,
|
|
StringMap<StringRef> &VariableTable,
|
|
const FileCheckRequest &Req,
|
|
std::vector<FileCheckDiag> *Diags) const;
|
|
size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
|
|
std::vector<const FileCheckPattern *> &NotStrings,
|
|
StringMap<StringRef> &VariableTable,
|
|
const FileCheckRequest &Req,
|
|
std::vector<FileCheckDiag> *Diags) const;
|
|
};
|
|
|
|
/// FileCheck class takes the request and exposes various methods that
|
|
/// use information from the request.
|
|
class FileCheck {
|
|
FileCheckRequest Req;
|
|
|
|
public:
|
|
FileCheck(FileCheckRequest Req) : Req(Req) {}
|
|
|
|
// 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.
|
|
Regex buildCheckPrefixRegex();
|
|
|
|
/// Read the check file, which specifies the sequence of expected strings.
|
|
///
|
|
/// The strings are added to the CheckStrings vector. Returns true in case of
|
|
/// an error, false otherwise.
|
|
bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
|
|
std::vector<FileCheckString> &CheckStrings);
|
|
|
|
bool ValidateCheckPrefixes();
|
|
|
|
/// Canonicalize whitespaces in the file. Line endings are replaced with
|
|
/// UNIX-style '\n'.
|
|
StringRef CanonicalizeFile(MemoryBuffer &MB,
|
|
SmallVectorImpl<char> &OutputBuffer);
|
|
|
|
/// Check the input to FileCheck provided in the \p Buffer against the \p
|
|
/// CheckStrings read from the check file.
|
|
///
|
|
/// Returns false if the input fails to satisfy the checks.
|
|
bool CheckInput(SourceMgr &SM, StringRef Buffer,
|
|
ArrayRef<FileCheckString> CheckStrings,
|
|
std::vector<FileCheckDiag> *Diags = nullptr);
|
|
};
|
|
} // namespace llvm
|
|
#endif
|