|  | //===--- tools/extra/clang-tidy/GlobList.cpp ------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "GlobList.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  |  | 
|  | namespace clang::tidy { | 
|  |  | 
|  | // Returns true if GlobList starts with the negative indicator ('-'), removes it | 
|  | // from the GlobList. | 
|  | static bool consumeNegativeIndicator(StringRef &GlobList) { | 
|  | GlobList = GlobList.trim(); | 
|  | return GlobList.consume_front("-"); | 
|  | } | 
|  |  | 
|  | // Extracts the first glob from the comma-separated list of globs, | 
|  | // removes it and the trailing comma from the GlobList and | 
|  | // returns the extracted glob. | 
|  | static llvm::StringRef extractNextGlob(StringRef &GlobList) { | 
|  | StringRef UntrimmedGlob = GlobList.substr(0, GlobList.find_first_of(",\n")); | 
|  | StringRef Glob = UntrimmedGlob.trim(); | 
|  | GlobList = GlobList.substr(UntrimmedGlob.size() + 1); | 
|  | return Glob; | 
|  | } | 
|  |  | 
|  | static llvm::Regex createRegexFromGlob(StringRef &Glob) { | 
|  | SmallString<128> RegexText("^"); | 
|  | StringRef MetaChars("()^$|*+?.[]\\{}"); | 
|  | for (char C : Glob) { | 
|  | if (C == '*') | 
|  | RegexText.push_back('.'); | 
|  | else if (MetaChars.contains(C)) | 
|  | RegexText.push_back('\\'); | 
|  | RegexText.push_back(C); | 
|  | } | 
|  | RegexText.push_back('$'); | 
|  | return {RegexText.str()}; | 
|  | } | 
|  |  | 
|  | GlobList::GlobList(StringRef Globs, bool KeepNegativeGlobs /* =true */) { | 
|  | Items.reserve(Globs.count(',') + Globs.count('\n') + 1); | 
|  | do { | 
|  | GlobListItem Item; | 
|  | Item.IsPositive = !consumeNegativeIndicator(Globs); | 
|  | Item.Text = extractNextGlob(Globs); | 
|  | Item.Regex = createRegexFromGlob(Item.Text); | 
|  | if (Item.IsPositive || KeepNegativeGlobs) | 
|  | Items.push_back(std::move(Item)); | 
|  | } while (!Globs.empty()); | 
|  | } | 
|  |  | 
|  | bool GlobList::contains(StringRef S) const { | 
|  | // Iterating the container backwards as the last match determins if S is in | 
|  | // the list. | 
|  | for (const GlobListItem &Item : llvm::reverse(Items)) { | 
|  | if (Item.Regex.match(S)) | 
|  | return Item.IsPositive; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CachedGlobList::contains(StringRef S) const { | 
|  | auto Entry = Cache.try_emplace(S); | 
|  | bool &Value = Entry.first->getValue(); | 
|  | // If the entry was just inserted, determine its required value. | 
|  | if (Entry.second) | 
|  | Value = GlobList::contains(S); | 
|  | return Value; | 
|  | } | 
|  |  | 
|  | } // namespace clang::tidy |