aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/FileCheck/FileCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/FileCheck/FileCheck.cpp')
-rw-r--r--llvm/lib/FileCheck/FileCheck.cpp318
1 files changed, 186 insertions, 132 deletions
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp
index 462f507..2b596fd 100644
--- a/llvm/lib/FileCheck/FileCheck.cpp
+++ b/llvm/lib/FileCheck/FileCheck.cpp
@@ -476,6 +476,7 @@ char OverflowError::ID = 0;
char UndefVarError::ID = 0;
char ErrorDiagnostic::ID = 0;
char NotFoundError::ID = 0;
+char ErrorReported::ID = 0;
Expected<NumericVariable *> Pattern::parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context,
@@ -1212,22 +1213,19 @@ void Pattern::AddBackrefToRegEx(unsigned BackrefNum) {
RegExStr += Backref;
}
-Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
- const SourceMgr &SM) const {
+Pattern::MatchResult Pattern::match(StringRef Buffer,
+ const SourceMgr &SM) const {
// If this is the EOF pattern, match it immediately.
- if (CheckTy == Check::CheckEOF) {
- MatchLen = 0;
- return Buffer.size();
- }
+ if (CheckTy == Check::CheckEOF)
+ return MatchResult(Buffer.size(), 0, Error::success());
// If this is a fixed string pattern, just match it now.
if (!FixedStr.empty()) {
- MatchLen = FixedStr.size();
size_t Pos =
IgnoreCase ? Buffer.find_lower(FixedStr) : Buffer.find(FixedStr);
if (Pos == StringRef::npos)
return make_error<NotFoundError>();
- return Pos;
+ return MatchResult(Pos, /*MatchLen=*/FixedStr.size(), Error::success());
}
// Regex match.
@@ -1250,7 +1248,7 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
Expected<std::string> Value = Substitution->getResult();
if (!Value) {
// Convert to an ErrorDiagnostic to get location information. This is
- // done here rather than PrintNoMatch since now we know which
+ // done here rather than printMatch/printNoMatch since now we know which
// substitution block caused the overflow.
Error Err =
handleErrors(Value.takeError(), [&](const OverflowError &E) {
@@ -1289,6 +1287,14 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
MatchInfo[VariableDef.second];
}
+ // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
+ // the required preceding newline, which is consumed by the pattern in the
+ // case of CHECK-EMPTY but not CHECK-NEXT.
+ size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
+ Match TheMatch;
+ TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip;
+ TheMatch.Len = FullMatch.size() - MatchStartSkip;
+
// If this defines any numeric variables, remember their values.
for (const auto &NumericVariableDef : NumericVariableDefs) {
const NumericVariableMatch &NumericVariableMatch =
@@ -1303,16 +1309,11 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
Expected<ExpressionValue> Value =
Format.valueFromStringRepr(MatchedValue, SM);
if (!Value)
- return Value.takeError();
+ return MatchResult(TheMatch, Value.takeError());
DefinedNumericVariable->setValue(*Value, MatchedValue);
}
- // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
- // the required preceding newline, which is consumed by the pattern in the
- // case of CHECK-EMPTY but not CHECK-NEXT.
- size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
- MatchLen = FullMatch.size() - MatchStartSkip;
- return FullMatch.data() - Buffer.data() + MatchStartSkip;
+ return MatchResult(TheMatch, Error::success());
}
unsigned Pattern::computeMatchDistance(StringRef Buffer) const {
@@ -1349,7 +1350,7 @@ void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
bool UndefSeen = false;
handleAllErrors(
MatchedValue.takeError(), [](const NotFoundError &E) {},
- // Handled in PrintNoMatch().
+ // Handled in printMatch and printNoMatch().
[](const ErrorDiagnostic &E) {},
// Handled in match().
[](const OverflowError &E) {},
@@ -1404,11 +1405,12 @@ void Pattern::printVariableDefs(const SourceMgr &SM,
for (const auto &VariableDef : NumericVariableDefs) {
VarCapture VC;
VC.Name = VariableDef.getKey();
- StringRef StrValue = VariableDef.getValue()
- .DefinedNumericVariable->getStringValue()
- .getValue();
- SMLoc Start = SMLoc::getFromPointer(StrValue.data());
- SMLoc End = SMLoc::getFromPointer(StrValue.data() + StrValue.size());
+ Optional<StringRef> StrValue =
+ VariableDef.getValue().DefinedNumericVariable->getStringValue();
+ if (!StrValue)
+ continue;
+ SMLoc Start = SMLoc::getFromPointer(StrValue->data());
+ SMLoc End = SMLoc::getFromPointer(StrValue->data() + StrValue->size());
VC.Range = SMRange(Start, End);
VarCaptures.push_back(VC);
}
@@ -2036,123 +2038,179 @@ bool FileCheck::readCheckFile(
return false;
}
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
- StringRef Prefix, SMLoc Loc, const Pattern &Pat,
- int MatchedCount, StringRef Buffer, size_t MatchPos,
- size_t MatchLen, const FileCheckRequest &Req,
- std::vector<FileCheckDiag> *Diags) {
+/// Returns either (1) \c ErrorSuccess if there was no error or (2)
+/// \c ErrorReported if an error was reported, such as an unexpected match.
+static Error printMatch(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ int MatchedCount, StringRef Buffer,
+ Pattern::MatchResult MatchResult,
+ const FileCheckRequest &Req,
+ std::vector<FileCheckDiag> *Diags) {
+ // Suppress some verbosity if there's no error.
+ bool HasError = !ExpectedMatch || MatchResult.TheError;
bool PrintDiag = true;
- if (ExpectedMatch) {
+ if (!HasError) {
if (!Req.Verbose)
- return;
+ return ErrorReported::reportedOrSuccess(HasError);
if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
- return;
+ return ErrorReported::reportedOrSuccess(HasError);
// Due to their verbosity, we don't print verbose diagnostics here if we're
- // gathering them for a different rendering, but we always print other
- // diagnostics.
+ // gathering them for Diags to be rendered elsewhere, but we always print
+ // other diagnostics.
PrintDiag = !Diags;
}
+
+ // Add "found" diagnostic, substitutions, and variable definitions to Diags.
FileCheckDiag::MatchType MatchTy = ExpectedMatch
? FileCheckDiag::MatchFoundAndExpected
: FileCheckDiag::MatchFoundButExcluded;
SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(),
- Buffer, MatchPos, MatchLen, Diags);
+ Buffer, MatchResult.TheMatch->Pos,
+ MatchResult.TheMatch->Len, Diags);
if (Diags) {
Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags);
Pat.printVariableDefs(SM, MatchTy, Diags);
}
- if (!PrintDiag)
- return;
+ if (!PrintDiag) {
+ assert(!HasError && "expected to report more diagnostics for error");
+ return ErrorReported::reportedOrSuccess(HasError);
+ }
+ // Print the match.
std::string Message = formatv("{0}: {1} string found in input",
Pat.getCheckTy().getDescription(Prefix),
(ExpectedMatch ? "expected" : "excluded"))
.str();
if (Pat.getCount() > 1)
Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
-
SM.PrintMessage(
Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
{MatchRange});
+
+ // Print additional information, which can be useful even if there are errors.
Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr);
Pat.printVariableDefs(SM, MatchTy, nullptr);
-}
-static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM,
- const FileCheckString &CheckStr, int MatchedCount,
- 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, MatchPos, MatchLen, Req, Diags);
-}
-
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
- StringRef Prefix, SMLoc Loc, const Pattern &Pat,
- int MatchedCount, StringRef Buffer,
- bool VerboseVerbose, std::vector<FileCheckDiag> *Diags,
- Error MatchErrors) {
- assert(MatchErrors && "Called on successful match");
+ // Print errors and add them to Diags. We report these errors after the match
+ // itself because we found them after the match. If we had found them before
+ // the match, we'd be in printNoMatch.
+ handleAllErrors(std::move(MatchResult.TheError),
+ [&](const ErrorDiagnostic &E) {
+ E.log(errs());
+ if (Diags) {
+ Diags->emplace_back(SM, Pat.getCheckTy(), Loc,
+ FileCheckDiag::MatchFoundErrorNote,
+ E.getRange(), E.getMessage().str());
+ }
+ });
+ return ErrorReported::reportedOrSuccess(HasError);
+}
+
+/// Returns either (1) \c ErrorSuccess if there was no error, or (2)
+/// \c ErrorReported if an error was reported, such as an expected match not
+/// found.
+static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ int MatchedCount, StringRef Buffer, Error MatchError,
+ bool VerboseVerbose,
+ std::vector<FileCheckDiag> *Diags) {
+ // Print any pattern errors, and record them to be added to Diags later.
+ bool HasError = ExpectedMatch;
+ bool HasPatternError = false;
+ FileCheckDiag::MatchType MatchTy = ExpectedMatch
+ ? FileCheckDiag::MatchNoneButExpected
+ : FileCheckDiag::MatchNoneAndExcluded;
+ SmallVector<std::string, 4> ErrorMsgs;
+ handleAllErrors(
+ std::move(MatchError),
+ [&](const ErrorDiagnostic &E) {
+ HasError = HasPatternError = true;
+ MatchTy = FileCheckDiag::MatchNoneForInvalidPattern;
+ E.log(errs());
+ if (Diags)
+ ErrorMsgs.push_back(E.getMessage().str());
+ },
+ // UndefVarError is reported in printSubstitutions below.
+ // FIXME: It probably should be handled as a pattern error and actually
+ // change the exit status to 1, even if !ExpectedMatch. To do so, we
+ // could stop calling printSubstitutions and actually report the error
+ // here as we do ErrorDiagnostic above.
+ [](const UndefVarError &E) {},
+ // NotFoundError is why printNoMatch was invoked.
+ [](const NotFoundError &E) {});
+
+ // Suppress some verbosity if there's no error.
bool PrintDiag = true;
- if (!ExpectedMatch) {
- if (!VerboseVerbose) {
- consumeError(std::move(MatchErrors));
- return;
- }
+ if (!HasError) {
+ if (!VerboseVerbose)
+ return ErrorReported::reportedOrSuccess(HasError);
// Due to their verbosity, we don't print verbose diagnostics here if we're
- // gathering them for a different rendering, but we always print other
- // diagnostics.
+ // gathering them for Diags to be rendered elsewhere, but we always print
+ // other diagnostics.
PrintDiag = !Diags;
}
- FileCheckDiag::MatchType MatchTy = ExpectedMatch
- ? FileCheckDiag::MatchNoneButExpected
- : FileCheckDiag::MatchNoneAndExcluded;
+ // Add "not found" diagnostic, substitutions, and pattern errors to Diags.
+ //
+ // We handle Diags a little differently than the errors we print directly:
+ // we add the "not found" diagnostic to Diags even if there are pattern
+ // errors. The reason is that we need to attach pattern errors as notes
+ // somewhere in the input, and the input search range from the "not found"
+ // diagnostic is all we have to anchor them.
SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(),
Buffer, 0, Buffer.size(), Diags);
- if (Diags)
+ if (Diags) {
+ SMRange NoteRange = SMRange(SearchRange.Start, SearchRange.Start);
+ for (StringRef ErrorMsg : ErrorMsgs)
+ Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange,
+ ErrorMsg);
Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags);
- if (!PrintDiag) {
- consumeError(std::move(MatchErrors));
- return;
}
-
- MatchErrors = handleErrors(std::move(MatchErrors),
- [](const ErrorDiagnostic &E) { E.log(errs()); });
-
- // No problem matching the string per se.
- if (!MatchErrors)
- return;
- consumeError(std::move(MatchErrors));
-
- // Print "not found" diagnostic.
- std::string Message = formatv("{0}: {1} string not found in input",
- Pat.getCheckTy().getDescription(Prefix),
- (ExpectedMatch ? "expected" : "excluded"))
- .str();
- if (Pat.getCount() > 1)
- Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
- SM.PrintMessage(
- Loc, ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark, Message);
-
- // Print the "scanning from here" line.
- SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note, "scanning from here");
-
- // Allow the pattern to print additional information if desired.
+ if (!PrintDiag) {
+ assert(!HasError && "expected to report more diagnostics for error");
+ return ErrorReported::reportedOrSuccess(HasError);
+ }
+
+ // Print "not found" diagnostic, except that's implied if we already printed a
+ // pattern error.
+ if (!HasPatternError) {
+ std::string Message = formatv("{0}: {1} string not found in input",
+ Pat.getCheckTy().getDescription(Prefix),
+ (ExpectedMatch ? "expected" : "excluded"))
+ .str();
+ if (Pat.getCount() > 1)
+ Message +=
+ formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
+ SM.PrintMessage(Loc,
+ ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark,
+ Message);
+ SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note,
+ "scanning from here");
+ }
+
+ // Print additional information, which can be useful even after a pattern
+ // error.
Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr);
-
if (ExpectedMatch)
Pat.printFuzzyMatch(SM, Buffer, Diags);
+ return ErrorReported::reportedOrSuccess(HasError);
}
-static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM,
- const FileCheckString &CheckStr, int MatchedCount,
- StringRef Buffer, bool VerboseVerbose,
- std::vector<FileCheckDiag> *Diags, Error MatchErrors) {
- PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat,
- MatchedCount, Buffer, VerboseVerbose, Diags,
- std::move(MatchErrors));
+/// Returns either (1) \c ErrorSuccess if there was no error, or (2)
+/// \c ErrorReported if an error was reported.
+static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM,
+ StringRef Prefix, SMLoc Loc, const Pattern &Pat,
+ int MatchedCount, StringRef Buffer,
+ Pattern::MatchResult MatchResult,
+ const FileCheckRequest &Req,
+ std::vector<FileCheckDiag> *Diags) {
+ if (MatchResult.TheMatch)
+ return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
+ std::move(MatchResult), Req, Diags);
+ return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
+ std::move(MatchResult.TheError), Req.VerboseVerbose,
+ Diags);
}
/// Counts the number of newlines in the specified range.
@@ -2204,24 +2262,23 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
assert(Pat.getCount() != 0 && "pattern count can not be zero");
for (int i = 1; i <= Pat.getCount(); i++) {
StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
- size_t CurrentMatchLen;
// get a match at current start point
- Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM);
+ Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM);
// report
- if (!MatchResult) {
- PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags,
- MatchResult.takeError());
+ if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, Loc,
+ Pat, i, MatchBuffer,
+ std::move(MatchResult), Req, Diags)) {
+ cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
return StringRef::npos;
}
- size_t MatchPos = *MatchResult;
- PrintMatch(true, SM, *this, i, MatchBuffer, MatchPos, CurrentMatchLen, Req,
- Diags);
+
+ size_t MatchPos = MatchResult.TheMatch->Pos;
if (i == 1)
FirstMatchPos = LastPos + MatchPos;
// move start point after the match
- LastMatchEnd += MatchPos + CurrentMatchLen;
+ LastMatchEnd += MatchPos + MatchResult.TheMatch->Len;
}
// Full match len counts from first match pos.
MatchLen = LastMatchEnd - FirstMatchPos;
@@ -2328,22 +2385,15 @@ bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
bool DirectiveFail = false;
for (const Pattern *Pat : NotStrings) {
assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
-
- size_t MatchLen = 0;
- Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM);
-
- if (!MatchResult) {
- PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer,
- Req.VerboseVerbose, Diags, MatchResult.takeError());
+ Pattern::MatchResult MatchResult = Pat->match(Buffer, SM);
+ if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix,
+ Pat->getLoc(), *Pat, 1, Buffer,
+ std::move(MatchResult), Req, Diags)) {
+ cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
+ DirectiveFail = true;
continue;
}
- size_t Pos = *MatchResult;
-
- PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen,
- Req, Diags);
- DirectiveFail = true;
}
-
return DirectiveFail;
}
@@ -2389,20 +2439,22 @@ size_t 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);
- Expected<size_t> MatchResult = Pat.match(MatchBuffer, MatchLen, SM);
+ Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM);
// With a group of CHECK-DAGs, a single mismatching means the match on
// that group of CHECK-DAGs fails immediately.
- if (!MatchResult) {
- PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer,
- Req.VerboseVerbose, Diags, MatchResult.takeError());
- return StringRef::npos;
+ if (MatchResult.TheError || Req.VerboseVerbose) {
+ if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix,
+ Pat.getLoc(), Pat, 1, MatchBuffer,
+ std::move(MatchResult), Req, Diags)) {
+ cantFail(
+ handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
+ return StringRef::npos;
+ }
}
- size_t MatchPosBuf = *MatchResult;
- // 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, MatchPos,
- MatchLen, Req, Diags);
+ MatchLen = MatchResult.TheMatch->Len;
+ // Re-calc it as the offset relative to the start of the original
+ // string.
+ MatchPos += MatchResult.TheMatch->Pos;
MatchRange M{MatchPos, MatchPos + MatchLen};
if (Req.AllowDeprecatedDagOverlap) {
// We don't need to track all matches in this mode, so we just maintain
@@ -2453,8 +2505,10 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
MatchPos = MI->End;
}
if (!Req.VerboseVerbose)
- PrintMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer, MatchPos,
- MatchLen, Req, Diags);
+ cantFail(printMatch(
+ /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
+ Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req,
+ Diags));
// Handle the end of a CHECK-DAG group.
if (std::next(PatItr) == PatEnd ||