aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/FileCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/FileCheck.cpp')
-rw-r--r--llvm/lib/Support/FileCheck.cpp171
1 files changed, 86 insertions, 85 deletions
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index 92c4264..e1564a4 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -269,10 +269,10 @@ bool FileCheckPattern::EvaluateExpression(StringRef Expr, std::string &Value) co
/// there is a match, the size of the matched string is returned in \p
/// MatchLen.
///
-/// The \p VariableTable StringMap provides the current values of filecheck
-/// variables and is updated if this match defines new values.
-size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen,
- StringMap<StringRef> &VariableTable) const {
+/// The GlobalVariableTable StringMap in the FileCheckPatternContext class
+/// instance provides the current values of FileCheck variables and is updated
+/// if this match defines new values.
+size_t FileCheckPattern::match(StringRef Buffer, size_t &MatchLen) const {
// If this is the EOF pattern, match it immediately.
if (CheckTy == Check::CheckEOF) {
MatchLen = 0;
@@ -302,14 +302,14 @@ size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen,
if (!EvaluateExpression(VariableUse.first, Value))
return StringRef::npos;
} else {
- StringMap<StringRef>::iterator it =
- VariableTable.find(VariableUse.first);
+ llvm::Optional<StringRef> ValueRef =
+ Context->getVarValue(VariableUse.first);
// If the variable is undefined, return an error.
- if (it == VariableTable.end())
+ if (!ValueRef)
return StringRef::npos;
// Look up the value and escape it so that we can put it into the regex.
- Value += Regex::escape(it->second);
+ Value += Regex::escape(*ValueRef);
}
// Plop it into the regex at the adjusted offset.
@@ -333,7 +333,8 @@ size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen,
// If this defines any variables, remember their values.
for (const auto &VariableDef : VariableDefs) {
assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
- VariableTable[VariableDef.first] = MatchInfo[VariableDef.second];
+ Context->GlobalVariableTable[VariableDef.first] =
+ MatchInfo[VariableDef.second];
}
// Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
@@ -344,13 +345,10 @@ size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen,
return FullMatch.data() - Buffer.data() + MatchStartSkip;
}
-
/// Computes an arbitrary estimate for the quality of matching this pattern at
/// the start of \p Buffer; a distance of zero should correspond to a perfect
/// match.
-unsigned
-FileCheckPattern::ComputeMatchDistance(StringRef Buffer,
- const StringMap<StringRef> &VariableTable) const {
+unsigned FileCheckPattern::computeMatchDistance(StringRef Buffer) const {
// Just compute the number of matching characters. For regular expressions, we
// just compare against the regex itself and hope for the best.
//
@@ -367,9 +365,8 @@ FileCheckPattern::ComputeMatchDistance(StringRef Buffer,
return BufferPrefix.edit_distance(ExampleString);
}
-void FileCheckPattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
- const StringMap<StringRef> &VariableTable,
- SMRange MatchRange) const {
+void FileCheckPattern::printVariableUses(const SourceMgr &SM, StringRef Buffer,
+ SMRange MatchRange) const {
// If this was a regular expression using variables, print the current
// variable values.
if (!VariableUses.empty()) {
@@ -388,16 +385,16 @@ void FileCheckPattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer,
OS.write_escaped(Var) << "\"";
}
} else {
- StringMap<StringRef>::const_iterator it = VariableTable.find(Var);
+ llvm::Optional<StringRef> VarValue = Context->getVarValue(Var);
// Check for undefined variable references.
- if (it == VariableTable.end()) {
+ if (!VarValue) {
OS << "uses undefined variable \"";
OS.write_escaped(Var) << "\"";
} else {
OS << "with variable \"";
OS.write_escaped(Var) << "\" equal to \"";
- OS.write_escaped(it->second) << "\"";
+ OS.write_escaped(*VarValue) << "\"";
}
}
@@ -429,9 +426,8 @@ static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
return Range;
}
-void FileCheckPattern::PrintFuzzyMatch(
+void FileCheckPattern::printFuzzyMatch(
const SourceMgr &SM, StringRef Buffer,
- const StringMap<StringRef> &VariableTable,
std::vector<FileCheckDiag> *Diags) const {
// Attempt to find the closest/best fuzzy match. Usually an error happens
// because some string in the output didn't exactly match. In these cases, we
@@ -453,7 +449,7 @@ void FileCheckPattern::PrintFuzzyMatch(
// Compute the "quality" of this match as an arbitrary combination of the
// match distance and the number of lines skipped to get to this match.
- unsigned Distance = ComputeMatchDistance(Buffer.substr(i), VariableTable);
+ unsigned Distance = computeMatchDistance(Buffer.substr(i));
double Quality = Distance + (NumLinesForward / 100.);
if (Quality < BestQuality || Best == StringRef::npos) {
@@ -477,6 +473,15 @@ void FileCheckPattern::PrintFuzzyMatch(
}
}
+llvm::Optional<StringRef>
+FileCheckPatternContext::getVarValue(StringRef VarName) {
+ auto VarIter = GlobalVariableTable.find(VarName);
+ if (VarIter == GlobalVariableTable.end())
+ return llvm::None;
+
+ return VarIter->second;
+}
+
/// Finds the closing sequence of a regex variable usage or definition.
///
/// \p Str has to point in the beginning of the definition (right after the
@@ -747,9 +752,11 @@ FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
///
/// The strings are added to the CheckStrings vector. Returns true in case of
/// an error, false otherwise.
-bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
- Regex &PrefixRE,
- std::vector<FileCheckString> &CheckStrings) {
+bool llvm::FileCheck::ReadCheckFile(
+ SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
+ std::vector<FileCheckString> &CheckStrings) {
+ PatternContext.defineCmdlineVariables(Req.GlobalDefines);
+
std::vector<FileCheckPattern> ImplicitNegativeChecks;
for (const auto &PatternString : Req.ImplicitCheckNot) {
// Create a buffer with fake command line content in order to display the
@@ -763,7 +770,8 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
- ImplicitNegativeChecks.push_back(FileCheckPattern(Check::CheckNot));
+ ImplicitNegativeChecks.push_back(
+ FileCheckPattern(Check::CheckNot, &PatternContext));
ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
"IMPLICIT-CHECK", SM, 0, Req);
}
@@ -826,7 +834,7 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
// Parse the pattern.
- FileCheckPattern P(CheckTy);
+ FileCheckPattern P(CheckTy, &PatternContext);
if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber, Req))
return true;
@@ -870,8 +878,9 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
// Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first
// prefix as a filler for the error message.
if (!DagNotMatches.empty()) {
- CheckStrings.emplace_back(FileCheckPattern(Check::CheckEOF), *Req.CheckPrefixes.begin(),
- SMLoc::getFromPointer(Buffer.data()));
+ CheckStrings.emplace_back(
+ FileCheckPattern(Check::CheckEOF, &PatternContext),
+ *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
@@ -896,8 +905,7 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer,
static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat,
- int MatchedCount, StringRef Buffer,
- StringMap<StringRef> &VariableTable, size_t MatchPos,
+ int MatchedCount, StringRef Buffer, size_t MatchPos,
size_t MatchLen, const FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) {
bool PrintDiag = true;
@@ -929,24 +937,22 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
{MatchRange});
- Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange);
+ Pat.printVariableUses(SM, Buffer, MatchRange);
}
static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
const FileCheckString &CheckStr, int MatchedCount,
- StringRef Buffer, StringMap<StringRef> &VariableTable,
- size_t MatchPos, size_t MatchLen, FileCheckRequest &Req,
+ StringRef Buffer, size_t MatchPos, size_t MatchLen,
+ FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) {
PrintMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
- MatchedCount, Buffer, VariableTable, MatchPos, MatchLen, Req,
- Diags);
+ MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags);
}
static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
StringRef Prefix, SMLoc Loc,
const FileCheckPattern &Pat, int MatchedCount,
- StringRef Buffer, StringMap<StringRef> &VariableTable,
- bool VerboseVerbose,
+ StringRef Buffer, bool VerboseVerbose,
std::vector<FileCheckDiag> *Diags) {
bool PrintDiag = true;
if (!ExpectedMatch) {
@@ -982,19 +988,18 @@ static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
// Allow the pattern to print additional information if desired.
- Pat.PrintVariableUses(SM, Buffer, VariableTable);
+ Pat.printVariableUses(SM, Buffer);
if (ExpectedMatch)
- Pat.PrintFuzzyMatch(SM, Buffer, VariableTable, Diags);
+ Pat.printFuzzyMatch(SM, Buffer, Diags);
}
static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
const FileCheckString &CheckStr, int MatchedCount,
- StringRef Buffer, StringMap<StringRef> &VariableTable,
- bool VerboseVerbose,
+ StringRef Buffer, bool VerboseVerbose,
std::vector<FileCheckDiag> *Diags) {
PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
- MatchedCount, Buffer, VariableTable, VerboseVerbose, Diags);
+ MatchedCount, Buffer, VerboseVerbose, Diags);
}
/// Count the number of newlines in the specified range.
@@ -1023,7 +1028,6 @@ static unsigned CountNumNewlinesBetween(StringRef Range,
/// Match check string and its "not strings" and/or "dag strings".
size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
bool IsLabelScanMode, size_t &MatchLen,
- StringMap<StringRef> &VariableTable,
FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) const {
size_t LastPos = 0;
@@ -1035,7 +1039,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
// over the block again (including the last CHECK-LABEL) in normal mode.
if (!IsLabelScanMode) {
// Match "dag strings" (with mixed "not strings" if any).
- LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable, Req, Diags);
+ LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
if (LastPos == StringRef::npos)
return StringRef::npos;
}
@@ -1050,18 +1054,17 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
size_t CurrentMatchLen;
// get a match at current start point
- size_t MatchPos = Pat.Match(MatchBuffer, CurrentMatchLen, VariableTable);
+ size_t MatchPos = Pat.match(MatchBuffer, CurrentMatchLen);
if (i == 1)
FirstMatchPos = LastPos + MatchPos;
// report
if (MatchPos == StringRef::npos) {
- PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable,
- Req.VerboseVerbose, Diags);
+ PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags);
return StringRef::npos;
}
- PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos,
- CurrentMatchLen, Req, Diags);
+ PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
+ Diags);
// move start point after the match
LastMatchEnd += MatchPos + CurrentMatchLen;
@@ -1096,7 +1099,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
// If this match had "not strings", verify that they don't exist in the
// skipped region.
- if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
+ if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
return StringRef::npos;
}
@@ -1170,22 +1173,21 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
bool FileCheckString::CheckNot(
const SourceMgr &SM, StringRef Buffer,
const std::vector<const FileCheckPattern *> &NotStrings,
- StringMap<StringRef> &VariableTable, const FileCheckRequest &Req,
- std::vector<FileCheckDiag> *Diags) const {
+ const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const {
for (const FileCheckPattern *Pat : NotStrings) {
assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
size_t MatchLen = 0;
- size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
+ size_t Pos = Pat->match(Buffer, MatchLen);
if (Pos == StringRef::npos) {
PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
- VariableTable, Req.VerboseVerbose, Diags);
+ Req.VerboseVerbose, Diags);
continue;
}
- PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, VariableTable,
- Pos, MatchLen, Req, Diags);
+ PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
+ Req, Diags);
return true;
}
@@ -1197,7 +1199,6 @@ bool FileCheckString::CheckNot(
size_t
FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
std::vector<const FileCheckPattern *> &NotStrings,
- StringMap<StringRef> &VariableTable,
const FileCheckRequest &Req,
std::vector<FileCheckDiag> *Diags) const {
if (DagNotStrings.empty())
@@ -1238,19 +1239,19 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// CHECK-DAG group.
for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
StringRef MatchBuffer = Buffer.substr(MatchPos);
- size_t MatchPosBuf = Pat.Match(MatchBuffer, MatchLen, VariableTable);
+ size_t MatchPosBuf = Pat.match(MatchBuffer, MatchLen);
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
if (MatchPosBuf == StringRef::npos) {
PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
- VariableTable, Req.VerboseVerbose, Diags);
+ Req.VerboseVerbose, Diags);
return StringRef::npos;
}
// Re-calc it as the offset relative to the start of the original string.
MatchPos += MatchPosBuf;
if (Req.VerboseVerbose)
- PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
- VariableTable, MatchPos, MatchLen, Req, Diags);
+ PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
+ MatchLen, Req, Diags);
MatchRange M{MatchPos, MatchPos + MatchLen};
if (Req.AllowDeprecatedDagOverlap) {
// We don't need to track all matches in this mode, so we just maintain
@@ -1297,8 +1298,8 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
MatchPos = MI->End;
}
if (!Req.VerboseVerbose)
- PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, VariableTable,
- MatchPos, MatchLen, Req, Diags);
+ PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
+ MatchLen, Req, Diags);
// Handle the end of a CHECK-DAG group.
if (std::next(PatItr) == PatEnd ||
@@ -1309,7 +1310,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// region.
StringRef SkippedRegion =
Buffer.slice(StartPos, MatchRanges.begin()->Pos);
- if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags))
+ if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();
@@ -1373,16 +1374,22 @@ Regex llvm::FileCheck::buildCheckPrefixRegex() {
return Regex(PrefixRegexStr);
}
-// Remove local variables from \p VariableTable. Global variables
-// (start with '$') are preserved.
-static void ClearLocalVars(StringMap<StringRef> &VariableTable) {
- SmallVector<StringRef, 16> LocalVars;
- for (const auto &Var : VariableTable)
+void FileCheckPatternContext::defineCmdlineVariables(
+ std::vector<std::string> &CmdlineDefines) {
+ assert(GlobalVariableTable.empty() &&
+ "Overriding defined variable with command-line variable definitions");
+ for (StringRef CmdlineDef : CmdlineDefines)
+ GlobalVariableTable.insert(CmdlineDef.split('='));
+}
+
+void FileCheckPatternContext::clearLocalVars() {
+ SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;
+ for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)
if (Var.first()[0] != '$')
- LocalVars.push_back(Var.first());
+ LocalPatternVars.push_back(Var.first());
- for (const auto &Var : LocalVars)
- VariableTable.erase(Var);
+ for (const auto &Var : LocalPatternVars)
+ GlobalVariableTable.erase(Var);
}
/// Check the input to FileCheck provided in the \p Buffer against the \p
@@ -1394,12 +1401,6 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
std::vector<FileCheckDiag> *Diags) {
bool ChecksFailed = false;
- /// VariableTable - This holds all the current filecheck variables.
- StringMap<StringRef> VariableTable;
-
- for (const auto& Def : Req.GlobalDefines)
- VariableTable.insert(StringRef(Def).split('='));
-
unsigned i = 0, j = 0, e = CheckStrings.size();
while (true) {
StringRef CheckRegion;
@@ -1414,10 +1415,10 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
// Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
size_t MatchLabelLen = 0;
- size_t MatchLabelPos = CheckLabelStr.Check(
- SM, Buffer, true, MatchLabelLen, VariableTable, Req, Diags);
+ size_t MatchLabelPos =
+ CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
if (MatchLabelPos == StringRef::npos)
- // Immediately bail of CHECK-LABEL fails, nothing else we can do.
+ // Immediately bail if CHECK-LABEL fails, nothing else we can do.
return false;
CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
@@ -1426,7 +1427,7 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
}
if (Req.EnableVarScope)
- ClearLocalVars(VariableTable);
+ PatternContext.clearLocalVars();
for (; i != j; ++i) {
const FileCheckString &CheckStr = CheckStrings[i];
@@ -1434,8 +1435,8 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer,
// Check each string within the scanned region, including a second check
// of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
size_t MatchLen = 0;
- size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,
- VariableTable, Req, Diags);
+ size_t MatchPos =
+ CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
if (MatchPos == StringRef::npos) {
ChecksFailed = true;