"this pattern occur which are not matched by a positive pattern"),
cl::value_desc("pattern"));
+static cl::opt<bool> AllowEmptyInput(
+ "allow-empty", cl::init(false),
+ cl::desc("Allow the input file to be empty. This is useful when making\n"
+ "checks that some error message does not occur, for example."));
+
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===//
CheckNone = 0,
CheckPlain,
CheckNext,
+ CheckSame,
CheckNot,
CheckDAG,
CheckLabel,
/// CheckNext - Verify there is a single line in the given buffer.
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
+ /// CheckSame - Verify there is no newline in the given buffer.
+ bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
+
/// CheckNot - Verify there's no "not strings" in the given buffer.
bool CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
///
/// \param PreserveHorizontal Don't squash consecutive horizontal whitespace
/// characters to a single space.
-static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB,
- bool PreserveHorizontal) {
+static std::unique_ptr<MemoryBuffer>
+CanonicalizeInputFile(std::unique_ptr<MemoryBuffer> MB,
+ bool PreserveHorizontal) {
SmallString<128> NewFile;
NewFile.reserve(MB->getBufferSize());
++Ptr;
}
- // Free the old buffer and return a new one.
- MemoryBuffer *MB2 =
- MemoryBuffer::getMemBufferCopy(NewFile.str(), MB->getBufferIdentifier());
-
- delete MB;
- return MB2;
+ return std::unique_ptr<MemoryBuffer>(
+ MemoryBuffer::getMemBufferCopy(NewFile.str(), MB->getBufferIdentifier()));
}
static bool IsPartOfWord(char c) {
case Check::CheckNext:
return sizeof("-NEXT:") - 1;
+ case Check::CheckSame:
+ return sizeof("-SAME:") - 1;
+
case Check::CheckNot:
return sizeof("-NOT:") - 1;
if (Rest.startswith("NEXT:"))
return Check::CheckNext;
+ if (Rest.startswith("SAME:"))
+ return Check::CheckSame;
+
if (Rest.startswith("NOT:"))
return Check::CheckNot;
// If we want to canonicalize whitespace, strip excess whitespace from the
// buffer containing the CHECK lines. Remove DOS style line endings.
- MemoryBuffer *F = CanonicalizeInputFile(FileOrErr.get().release(),
- NoCanonicalizeWhiteSpace);
-
- SM.AddNewSourceBuffer(F, SMLoc());
+ std::unique_ptr<MemoryBuffer> F = CanonicalizeInputFile(
+ std::move(FileOrErr.get()), NoCanonicalizeWhiteSpace);
// Find all instances of CheckPrefix followed by : in the file.
StringRef Buffer = F->getBuffer();
+ SM.AddNewSourceBuffer(std::move(F), SMLoc());
+
std::vector<Pattern> ImplicitNegativeChecks;
for (const auto &PatternString : ImplicitCheckNot) {
// Create a buffer with fake command line content in order to display the
// command line option responsible for the specific implicit CHECK-NOT.
std::string Prefix = std::string("-") + ImplicitCheckNot.ArgStr + "='";
std::string Suffix = "'";
- MemoryBuffer *CmdLine = MemoryBuffer::getMemBufferCopy(
+ std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
Prefix + PatternString + Suffix, "command line");
+
StringRef PatternInBuffer =
CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
- SM.AddNewSourceBuffer(CmdLine, SMLoc());
+ SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
ImplicitNegativeChecks.push_back(Pattern(Check::CheckNot));
ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
Buffer = Buffer.substr(EOL);
// Verify that CHECK-NEXT lines have at least one CHECK line before them.
- if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) {
+ if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) &&
+ CheckStrings.empty()) {
+ StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME";
SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
SourceMgr::DK_Error,
- "found '" + UsedPrefix + "-NEXT:' without previous '"
+ "found '" + UsedPrefix + "-" + Type + "' without previous '"
+ UsedPrefix + ": line");
return true;
}
if (CheckNext(SM, SkippedRegion))
return StringRef::npos;
+ // If this check is a "CHECK-SAME", verify that the previous match was on
+ // the same line (i.e. that there is no newline between them).
+ if (CheckSame(SM, SkippedRegion))
+ return StringRef::npos;
+
// If this match had "not strings", verify that they don't exist in the
// skipped region.
if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return false;
}
+bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
+ if (CheckTy != Check::CheckSame)
+ return false;
+
+ // Count the number of newlines between the previous match and this one.
+ assert(Buffer.data() !=
+ SM.getMemoryBuffer(SM.FindBufferContainingLoc(
+ SMLoc::getFromPointer(Buffer.data())))
+ ->getBufferStart() &&
+ "CHECK-SAME can't be the first check in a file");
+
+ const char *FirstNewLine = nullptr;
+ unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
+
+ if (NumNewLines != 0) {
+ SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ Prefix +
+ "-SAME: is not on the same line as the previous match");
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
+ "'next' match was here");
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
+ "previous match ended here");
+ return true;
+ }
+
+ return false;
+}
+
bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
const std::vector<const Pattern *> &NotStrings,
StringMap<StringRef> &VariableTable) const {
if (Prefix == "")
return false;
- if (!PrefixSet.insert(Prefix))
+ if (!PrefixSet.insert(Prefix).second)
return false;
if (!ValidateCheckPrefix(Prefix))
<< "': " << EC.message() << '\n';
return 2;
}
- std::unique_ptr<MemoryBuffer> File = std::move(FileOrErr.get());
+ std::unique_ptr<MemoryBuffer> &File = FileOrErr.get();
- if (File->getBufferSize() == 0) {
+ if (File->getBufferSize() == 0 && !AllowEmptyInput) {
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
return 2;
}
// Remove duplicate spaces in the input file if requested.
// Remove DOS style line endings.
- MemoryBuffer *F =
- CanonicalizeInputFile(File.release(), NoCanonicalizeWhiteSpace);
-
- SM.AddNewSourceBuffer(F, SMLoc());
-
- /// VariableTable - This holds all the current filecheck variables.
- StringMap<StringRef> VariableTable;
+ std::unique_ptr<MemoryBuffer> F =
+ CanonicalizeInputFile(std::move(File), NoCanonicalizeWhiteSpace);
// Check that we have all of the expected strings, in order, in the input
// file.
StringRef Buffer = F->getBuffer();
+ SM.AddNewSourceBuffer(std::move(F), SMLoc());
+
+ /// VariableTable - This holds all the current filecheck variables.
+ StringMap<StringRef> VariableTable;
+
bool hasError = false;
unsigned i = 0, j = 0, e = CheckStrings.size();