1 //===--- tools/extra/clang-tidy/GlobList.cpp ------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "GlobList.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/SmallString.h" 12 13 namespace clang::tidy { 14 15 // Returns true if GlobList starts with the negative indicator ('-'), removes it 16 // from the GlobList. consumeNegativeIndicator(StringRef & GlobList)17static bool consumeNegativeIndicator(StringRef &GlobList) { 18 GlobList = GlobList.trim(); 19 return GlobList.consume_front("-"); 20 } 21 22 // Extracts the first glob from the comma-separated list of globs, 23 // removes it and the trailing comma from the GlobList and 24 // returns the extracted glob. extractNextGlob(StringRef & GlobList)25static llvm::StringRef extractNextGlob(StringRef &GlobList) { 26 StringRef UntrimmedGlob = GlobList.substr(0, GlobList.find_first_of(",\n")); 27 StringRef Glob = UntrimmedGlob.trim(); 28 GlobList = GlobList.substr(UntrimmedGlob.size() + 1); 29 return Glob; 30 } 31 createRegexFromGlob(StringRef & Glob)32static llvm::Regex createRegexFromGlob(StringRef &Glob) { 33 SmallString<128> RegexText("^"); 34 StringRef MetaChars("()^$|*+?.[]\\{}"); 35 for (char C : Glob) { 36 if (C == '*') 37 RegexText.push_back('.'); 38 else if (MetaChars.contains(C)) 39 RegexText.push_back('\\'); 40 RegexText.push_back(C); 41 } 42 RegexText.push_back('$'); 43 return {RegexText.str()}; 44 } 45 GlobList(StringRef Globs,bool KeepNegativeGlobs)46GlobList::GlobList(StringRef Globs, bool KeepNegativeGlobs /* =true */) { 47 Items.reserve(Globs.count(',') + Globs.count('\n') + 1); 48 do { 49 GlobListItem Item; 50 Item.IsPositive = !consumeNegativeIndicator(Globs); 51 Item.Text = extractNextGlob(Globs); 52 Item.Regex = createRegexFromGlob(Item.Text); 53 if (Item.IsPositive || KeepNegativeGlobs) 54 Items.push_back(std::move(Item)); 55 } while (!Globs.empty()); 56 } 57 contains(StringRef S) const58bool GlobList::contains(StringRef S) const { 59 // Iterating the container backwards as the last match determins if S is in 60 // the list. 61 for (const GlobListItem &Item : llvm::reverse(Items)) { 62 if (Item.Regex.match(S)) 63 return Item.IsPositive; 64 } 65 return false; 66 } 67 contains(StringRef S) const68bool CachedGlobList::contains(StringRef S) const { 69 auto Entry = Cache.try_emplace(S); 70 bool &Value = Entry.first->getValue(); 71 // If the entry was just inserted, determine its required value. 72 if (Entry.second) 73 Value = GlobList::contains(S); 74 return Value; 75 } 76 77 } // namespace clang::tidy 78