diff options
Diffstat (limited to 'llvm/lib/FileCheck/FileCheck.cpp')
-rw-r--r-- | llvm/lib/FileCheck/FileCheck.cpp | 102 |
1 files changed, 62 insertions, 40 deletions
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp index bef6dd6..ac8f52d 100644 --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -1634,6 +1634,60 @@ static size_t SkipWord(StringRef Str, size_t Loc) { return Loc; } +static const char *DefaultCheckPrefixes[] = {"CHECK"}; +static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; + +static void addDefaultPrefixes(FileCheckRequest &Req) { + if (Req.CheckPrefixes.empty()) { + for (const char *Prefix : DefaultCheckPrefixes) + Req.CheckPrefixes.push_back(Prefix); + Req.IsDefaultCheckPrefix = true; + } + if (Req.CommentPrefixes.empty()) + for (const char *Prefix : DefaultCommentPrefixes) + Req.CommentPrefixes.push_back(Prefix); +} + +struct PrefixMatcher { + /// Prefixes and their first occurrence past the current position. + SmallVector<std::pair<StringRef, size_t>> Prefixes; + StringRef Input; + + PrefixMatcher(ArrayRef<StringRef> CheckPrefixes, + ArrayRef<StringRef> CommentPrefixes, StringRef Input) + : Input(Input) { + for (StringRef Prefix : CheckPrefixes) + Prefixes.push_back({Prefix, Input.find(Prefix)}); + for (StringRef Prefix : CommentPrefixes) + Prefixes.push_back({Prefix, Input.find(Prefix)}); + + // Sort by descending length. + llvm::sort(Prefixes, + [](auto A, auto B) { return A.first.size() > B.first.size(); }); + } + + /// Find the next match of a prefix in Buffer. + /// Returns empty StringRef if not found. + StringRef match(StringRef Buffer) { + assert(Buffer.data() >= Input.data() && + Buffer.data() + Buffer.size() == Input.data() + Input.size() && + "Buffer must be suffix of Input"); + + size_t From = Buffer.data() - Input.data(); + StringRef Match; + for (auto &[Prefix, Pos] : Prefixes) { + // If the last occurrence was before From, find the next one after From. + if (Pos < From) + Pos = Input.find(Prefix, From); + // Find the first prefix with the lowest position. + if (Pos != StringRef::npos && + (Match.empty() || size_t(Match.data() - Input.data()) > Pos)) + Match = StringRef(Input.substr(Pos, Prefix.size())); + } + return Match; + } +}; + /// Searches the buffer for the first prefix in the prefix regular expression. /// /// This searches the buffer using the provided regular expression, however it @@ -1658,20 +1712,16 @@ static size_t SkipWord(StringRef Str, size_t Loc) { /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy /// is unspecified. static std::pair<StringRef, StringRef> -FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE, +FindFirstMatchingPrefix(const FileCheckRequest &Req, PrefixMatcher &Matcher, StringRef &Buffer, unsigned &LineNumber, Check::FileCheckType &CheckTy) { - SmallVector<StringRef, 2> Matches; - while (!Buffer.empty()) { - // Find the first (longest) match using the RE. - if (!PrefixRE.match(Buffer, &Matches)) + // Find the first (longest) prefix match. + StringRef Prefix = Matcher.match(Buffer); + if (Prefix.empty()) // No match at all, bail. return {StringRef(), StringRef()}; - StringRef Prefix = Matches[0]; - Matches.clear(); - assert(Prefix.data() >= Buffer.data() && Prefix.data() < Buffer.data() + Buffer.size() && "Prefix doesn't start inside of buffer!"); @@ -1720,7 +1770,7 @@ FileCheck::FileCheck(FileCheckRequest Req) FileCheck::~FileCheck() = default; bool FileCheck::readCheckFile( - SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, + SourceMgr &SM, StringRef Buffer, std::pair<unsigned, unsigned> *ImpPatBufferIDRange) { if (ImpPatBufferIDRange) ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0; @@ -1769,6 +1819,8 @@ bool FileCheck::readCheckFile( // found. unsigned LineNumber = 1; + addDefaultPrefixes(Req); + PrefixMatcher Matcher(Req.CheckPrefixes, Req.CommentPrefixes, Buffer); std::set<StringRef> PrefixesNotFound(Req.CheckPrefixes.begin(), Req.CheckPrefixes.end()); const size_t DistinctPrefixes = PrefixesNotFound.size(); @@ -1779,7 +1831,7 @@ bool FileCheck::readCheckFile( StringRef UsedPrefix; StringRef AfterSuffix; std::tie(UsedPrefix, AfterSuffix) = - FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy); + FindFirstMatchingPrefix(Req, Matcher, Buffer, LineNumber, CheckTy); if (UsedPrefix.empty()) break; if (CheckTy != Check::CheckComment) @@ -2431,9 +2483,6 @@ static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, return true; } -static const char *DefaultCheckPrefixes[] = {"CHECK"}; -static const char *DefaultCommentPrefixes[] = {"COM", "RUN"}; - bool FileCheck::ValidateCheckPrefixes() { StringSet<> UniquePrefixes; // Add default prefixes to catch user-supplied duplicates of them below. @@ -2454,33 +2503,6 @@ bool FileCheck::ValidateCheckPrefixes() { return true; } -Regex FileCheck::buildCheckPrefixRegex() { - if (Req.CheckPrefixes.empty()) { - for (const char *Prefix : DefaultCheckPrefixes) - Req.CheckPrefixes.push_back(Prefix); - Req.IsDefaultCheckPrefix = true; - } - if (Req.CommentPrefixes.empty()) { - for (const char *Prefix : DefaultCommentPrefixes) - Req.CommentPrefixes.push_back(Prefix); - } - - // We already validated the contents of CheckPrefixes and CommentPrefixes so - // just concatenate them as alternatives. - SmallString<32> PrefixRegexStr; - for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) { - if (I != 0) - PrefixRegexStr.push_back('|'); - PrefixRegexStr.append(Req.CheckPrefixes[I]); - } - for (StringRef Prefix : Req.CommentPrefixes) { - PrefixRegexStr.push_back('|'); - PrefixRegexStr.append(Prefix); - } - - return Regex(PrefixRegexStr); -} - Error FileCheckPatternContext::defineCmdlineVariables( ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) { assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() && |