1*5ffd83dbSDimitry Andric //===--- Marshallers.cpp ----------------------------------------*- C++ -*-===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric 9*5ffd83dbSDimitry Andric #include "Marshallers.h" 10*5ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 11*5ffd83dbSDimitry Andric #include "llvm/ADT/Optional.h" 12*5ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h" 13*5ffd83dbSDimitry Andric #include "llvm/Support/Regex.h" 14*5ffd83dbSDimitry Andric #include <string> 15*5ffd83dbSDimitry Andric 16*5ffd83dbSDimitry Andric static llvm::Optional<std::string> 17*5ffd83dbSDimitry Andric getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed, 18*5ffd83dbSDimitry Andric llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) { 19*5ffd83dbSDimitry Andric if (MaxEditDistance != ~0U) 20*5ffd83dbSDimitry Andric ++MaxEditDistance; 21*5ffd83dbSDimitry Andric llvm::StringRef Res; 22*5ffd83dbSDimitry Andric for (const llvm::StringRef &Item : Allowed) { 23*5ffd83dbSDimitry Andric if (Item.equals_lower(Search)) { 24*5ffd83dbSDimitry Andric assert(!Item.equals(Search) && "This should be handled earlier on."); 25*5ffd83dbSDimitry Andric MaxEditDistance = 1; 26*5ffd83dbSDimitry Andric Res = Item; 27*5ffd83dbSDimitry Andric continue; 28*5ffd83dbSDimitry Andric } 29*5ffd83dbSDimitry Andric unsigned Distance = Item.edit_distance(Search); 30*5ffd83dbSDimitry Andric if (Distance < MaxEditDistance) { 31*5ffd83dbSDimitry Andric MaxEditDistance = Distance; 32*5ffd83dbSDimitry Andric Res = Item; 33*5ffd83dbSDimitry Andric } 34*5ffd83dbSDimitry Andric } 35*5ffd83dbSDimitry Andric if (!Res.empty()) 36*5ffd83dbSDimitry Andric return Res.str(); 37*5ffd83dbSDimitry Andric if (!DropPrefix.empty()) { 38*5ffd83dbSDimitry Andric --MaxEditDistance; // Treat dropping the prefix as 1 edit 39*5ffd83dbSDimitry Andric for (const llvm::StringRef &Item : Allowed) { 40*5ffd83dbSDimitry Andric auto NoPrefix = Item; 41*5ffd83dbSDimitry Andric if (!NoPrefix.consume_front(DropPrefix)) 42*5ffd83dbSDimitry Andric continue; 43*5ffd83dbSDimitry Andric if (NoPrefix.equals_lower(Search)) { 44*5ffd83dbSDimitry Andric if (NoPrefix.equals(Search)) 45*5ffd83dbSDimitry Andric return Item.str(); 46*5ffd83dbSDimitry Andric MaxEditDistance = 1; 47*5ffd83dbSDimitry Andric Res = Item; 48*5ffd83dbSDimitry Andric continue; 49*5ffd83dbSDimitry Andric } 50*5ffd83dbSDimitry Andric unsigned Distance = NoPrefix.edit_distance(Search); 51*5ffd83dbSDimitry Andric if (Distance < MaxEditDistance) { 52*5ffd83dbSDimitry Andric MaxEditDistance = Distance; 53*5ffd83dbSDimitry Andric Res = Item; 54*5ffd83dbSDimitry Andric } 55*5ffd83dbSDimitry Andric } 56*5ffd83dbSDimitry Andric if (!Res.empty()) 57*5ffd83dbSDimitry Andric return Res.str(); 58*5ffd83dbSDimitry Andric } 59*5ffd83dbSDimitry Andric return llvm::None; 60*5ffd83dbSDimitry Andric } 61*5ffd83dbSDimitry Andric 62*5ffd83dbSDimitry Andric llvm::Optional<std::string> 63*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 64*5ffd83dbSDimitry Andric clang::attr::Kind>::getBestGuess(const VariantValue &Value) { 65*5ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 66*5ffd83dbSDimitry Andric #define ATTR(X) "attr::" #X, 67*5ffd83dbSDimitry Andric #include "clang/Basic/AttrList.inc" 68*5ffd83dbSDimitry Andric }; 69*5ffd83dbSDimitry Andric if (Value.isString()) 70*5ffd83dbSDimitry Andric return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), 71*5ffd83dbSDimitry Andric "attr::"); 72*5ffd83dbSDimitry Andric return llvm::None; 73*5ffd83dbSDimitry Andric } 74*5ffd83dbSDimitry Andric 75*5ffd83dbSDimitry Andric llvm::Optional<std::string> 76*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 77*5ffd83dbSDimitry Andric clang::CastKind>::getBestGuess(const VariantValue &Value) { 78*5ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 79*5ffd83dbSDimitry Andric #define CAST_OPERATION(Name) "CK_" #Name, 80*5ffd83dbSDimitry Andric #include "clang/AST/OperationKinds.def" 81*5ffd83dbSDimitry Andric }; 82*5ffd83dbSDimitry Andric if (Value.isString()) 83*5ffd83dbSDimitry Andric return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), 84*5ffd83dbSDimitry Andric "CK_"); 85*5ffd83dbSDimitry Andric return llvm::None; 86*5ffd83dbSDimitry Andric } 87*5ffd83dbSDimitry Andric 88*5ffd83dbSDimitry Andric llvm::Optional<std::string> 89*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 90*5ffd83dbSDimitry Andric clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) { 91*5ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 92*5ffd83dbSDimitry Andric #define OMP_CLAUSE_CLASS(Enum, Str, Class) #Enum, 93*5ffd83dbSDimitry Andric #include "llvm/Frontend/OpenMP/OMPKinds.def" 94*5ffd83dbSDimitry Andric }; 95*5ffd83dbSDimitry Andric if (Value.isString()) 96*5ffd83dbSDimitry Andric return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), 97*5ffd83dbSDimitry Andric "OMPC_"); 98*5ffd83dbSDimitry Andric return llvm::None; 99*5ffd83dbSDimitry Andric } 100*5ffd83dbSDimitry Andric 101*5ffd83dbSDimitry Andric llvm::Optional<std::string> 102*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 103*5ffd83dbSDimitry Andric clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) { 104*5ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 105*5ffd83dbSDimitry Andric #define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 106*5ffd83dbSDimitry Andric #define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 107*5ffd83dbSDimitry Andric #include "clang/Basic/TokenKinds.def" 108*5ffd83dbSDimitry Andric }; 109*5ffd83dbSDimitry Andric if (Value.isString()) 110*5ffd83dbSDimitry Andric return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), 111*5ffd83dbSDimitry Andric "UETT_"); 112*5ffd83dbSDimitry Andric return llvm::None; 113*5ffd83dbSDimitry Andric } 114*5ffd83dbSDimitry Andric 115*5ffd83dbSDimitry Andric static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags> 116*5ffd83dbSDimitry Andric RegexMap[] = { 117*5ffd83dbSDimitry Andric {"NoFlags", llvm::Regex::RegexFlags::NoFlags}, 118*5ffd83dbSDimitry Andric {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase}, 119*5ffd83dbSDimitry Andric {"Newline", llvm::Regex::RegexFlags::Newline}, 120*5ffd83dbSDimitry Andric {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex}, 121*5ffd83dbSDimitry Andric }; 122*5ffd83dbSDimitry Andric 123*5ffd83dbSDimitry Andric llvm::Optional<llvm::Regex::RegexFlags> getRegexFlag(llvm::StringRef Flag) { 124*5ffd83dbSDimitry Andric for (const auto &StringFlag : RegexMap) { 125*5ffd83dbSDimitry Andric if (Flag == StringFlag.first) 126*5ffd83dbSDimitry Andric return StringFlag.second; 127*5ffd83dbSDimitry Andric } 128*5ffd83dbSDimitry Andric return llvm::None; 129*5ffd83dbSDimitry Andric } 130*5ffd83dbSDimitry Andric 131*5ffd83dbSDimitry Andric llvm::Optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) { 132*5ffd83dbSDimitry Andric for (const auto &StringFlag : RegexMap) { 133*5ffd83dbSDimitry Andric if (Flag.edit_distance(StringFlag.first) < 3) 134*5ffd83dbSDimitry Andric return StringFlag.first; 135*5ffd83dbSDimitry Andric } 136*5ffd83dbSDimitry Andric return llvm::None; 137*5ffd83dbSDimitry Andric } 138*5ffd83dbSDimitry Andric 139*5ffd83dbSDimitry Andric llvm::Optional<llvm::Regex::RegexFlags> 140*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 141*5ffd83dbSDimitry Andric llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) { 142*5ffd83dbSDimitry Andric llvm::Optional<llvm::Regex::RegexFlags> Flag; 143*5ffd83dbSDimitry Andric SmallVector<StringRef, 4> Split; 144*5ffd83dbSDimitry Andric Flags.split(Split, '|', -1, false); 145*5ffd83dbSDimitry Andric for (StringRef OrFlag : Split) { 146*5ffd83dbSDimitry Andric if (llvm::Optional<llvm::Regex::RegexFlags> NextFlag = 147*5ffd83dbSDimitry Andric getRegexFlag(OrFlag.trim())) 148*5ffd83dbSDimitry Andric Flag = Flag.getValueOr(llvm::Regex::NoFlags) | *NextFlag; 149*5ffd83dbSDimitry Andric else 150*5ffd83dbSDimitry Andric return None; 151*5ffd83dbSDimitry Andric } 152*5ffd83dbSDimitry Andric return Flag; 153*5ffd83dbSDimitry Andric } 154*5ffd83dbSDimitry Andric 155*5ffd83dbSDimitry Andric llvm::Optional<std::string> 156*5ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 157*5ffd83dbSDimitry Andric llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) { 158*5ffd83dbSDimitry Andric if (!Value.isString()) 159*5ffd83dbSDimitry Andric return llvm::None; 160*5ffd83dbSDimitry Andric SmallVector<StringRef, 4> Split; 161*5ffd83dbSDimitry Andric llvm::StringRef(Value.getString()).split(Split, '|', -1, false); 162*5ffd83dbSDimitry Andric for (llvm::StringRef &Flag : Split) { 163*5ffd83dbSDimitry Andric if (llvm::Optional<llvm::StringRef> BestGuess = 164*5ffd83dbSDimitry Andric getCloseRegexMatch(Flag.trim())) 165*5ffd83dbSDimitry Andric Flag = *BestGuess; 166*5ffd83dbSDimitry Andric else 167*5ffd83dbSDimitry Andric return None; 168*5ffd83dbSDimitry Andric } 169*5ffd83dbSDimitry Andric if (Split.empty()) 170*5ffd83dbSDimitry Andric return None; 171*5ffd83dbSDimitry Andric return llvm::join(Split, " | "); 172*5ffd83dbSDimitry Andric } 173