+
+ 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 {
+ for (const Pattern *Pat : NotStrings) {
+ assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
+
+ size_t MatchLen = 0;
+ size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable);
+
+ if (Pos == StringRef::npos) continue;
+
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()+Pos),
+ SourceMgr::DK_Error,
+ Prefix + "-NOT: string occurred!");
+ SM.PrintMessage(Pat->getLoc(), SourceMgr::DK_Note,
+ Prefix + "-NOT: pattern specified here");
+ return true;
+ }
+
+ return false;
+}
+
+size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
+ std::vector<const Pattern *> &NotStrings,
+ StringMap<StringRef> &VariableTable) const {
+ if (DagNotStrings.empty())
+ return 0;
+
+ size_t LastPos = 0;
+ size_t StartPos = LastPos;
+
+ for (const Pattern &Pat : DagNotStrings) {
+ assert((Pat.getCheckTy() == Check::CheckDAG ||
+ Pat.getCheckTy() == Check::CheckNot) &&
+ "Invalid CHECK-DAG or CHECK-NOT!");
+
+ if (Pat.getCheckTy() == Check::CheckNot) {
+ NotStrings.push_back(&Pat);
+ continue;
+ }
+
+ assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
+
+ size_t MatchLen = 0, MatchPos;
+
+ // CHECK-DAG always matches from the start.
+ StringRef MatchBuffer = Buffer.substr(StartPos);
+ MatchPos = Pat.Match(MatchBuffer, MatchLen, VariableTable);
+ // With a group of CHECK-DAGs, a single mismatching means the match on
+ // that group of CHECK-DAGs fails immediately.
+ if (MatchPos == StringRef::npos) {
+ PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable);
+ return StringRef::npos;
+ }
+ // Re-calc it as the offset relative to the start of the original string.
+ MatchPos += StartPos;
+
+ if (!NotStrings.empty()) {
+ if (MatchPos < LastPos) {
+ // Reordered?
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + MatchPos),
+ SourceMgr::DK_Error,
+ Prefix + "-DAG: found a match of CHECK-DAG"
+ " reordering across a CHECK-NOT");
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + LastPos),
+ SourceMgr::DK_Note,
+ Prefix + "-DAG: the farthest match of CHECK-DAG"
+ " is found here");
+ SM.PrintMessage(NotStrings[0]->getLoc(), SourceMgr::DK_Note,
+ Prefix + "-NOT: the crossed pattern specified"
+ " here");
+ SM.PrintMessage(Pat.getLoc(), SourceMgr::DK_Note,
+ Prefix + "-DAG: the reordered pattern specified"
+ " here");
+ return StringRef::npos;
+ }
+ // All subsequent CHECK-DAGs should be matched from the farthest
+ // position of all precedent CHECK-DAGs (including this one.)
+ StartPos = LastPos;
+ // If there's CHECK-NOTs between two CHECK-DAGs or from CHECK to
+ // CHECK-DAG, verify that there's no 'not' strings occurred in that
+ // region.
+ StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
+ if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
+ return StringRef::npos;
+ // Clear "not strings".
+ NotStrings.clear();
+ }
+
+ // Update the last position with CHECK-DAG matches.
+ LastPos = std::max(MatchPos + MatchLen, LastPos);
+ }
+
+ return LastPos;
+}
+
+// A check prefix must contain only alphanumeric, hyphens and underscores.
+static bool ValidateCheckPrefix(StringRef CheckPrefix) {
+ Regex Validator("^[a-zA-Z0-9_-]*$");
+ return Validator.match(CheckPrefix);
+}
+
+static bool ValidateCheckPrefixes() {
+ StringSet<> PrefixSet;
+
+ for (StringRef Prefix : CheckPrefixes) {
+ // Reject empty prefixes.
+ if (Prefix == "")
+ return false;
+
+ if (!PrefixSet.insert(Prefix).second)
+ return false;
+
+ if (!ValidateCheckPrefix(Prefix))
+ return false;
+ }
+
+ return true;
+}
+
+// I don't think there's a way to specify an initial value for cl::list,
+// so if nothing was specified, add the default
+static void AddCheckPrefixIfNeeded() {
+ if (CheckPrefixes.empty())
+ CheckPrefixes.push_back("CHECK");