15ffd83dbSDimitry Andric //===--- Marshallers.cpp ----------------------------------------*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "Marshallers.h" 105ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 115ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h" 125ffd83dbSDimitry Andric #include "llvm/Support/Regex.h" 13bdd1243dSDimitry Andric #include <optional> 145ffd83dbSDimitry Andric #include <string> 155ffd83dbSDimitry Andric 16bdd1243dSDimitry Andric static std::optional<std::string> 175ffd83dbSDimitry Andric getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed, 185ffd83dbSDimitry Andric llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) { 195ffd83dbSDimitry Andric if (MaxEditDistance != ~0U) 205ffd83dbSDimitry Andric ++MaxEditDistance; 215ffd83dbSDimitry Andric llvm::StringRef Res; 225ffd83dbSDimitry Andric for (const llvm::StringRef &Item : Allowed) { 23fe6060f1SDimitry Andric if (Item.equals_insensitive(Search)) { 24*0fca6ea1SDimitry Andric assert(Item != Search && "This should be handled earlier on."); 255ffd83dbSDimitry Andric MaxEditDistance = 1; 265ffd83dbSDimitry Andric Res = Item; 275ffd83dbSDimitry Andric continue; 285ffd83dbSDimitry Andric } 295ffd83dbSDimitry Andric unsigned Distance = Item.edit_distance(Search); 305ffd83dbSDimitry Andric if (Distance < MaxEditDistance) { 315ffd83dbSDimitry Andric MaxEditDistance = Distance; 325ffd83dbSDimitry Andric Res = Item; 335ffd83dbSDimitry Andric } 345ffd83dbSDimitry Andric } 355ffd83dbSDimitry Andric if (!Res.empty()) 365ffd83dbSDimitry Andric return Res.str(); 375ffd83dbSDimitry Andric if (!DropPrefix.empty()) { 385ffd83dbSDimitry Andric --MaxEditDistance; // Treat dropping the prefix as 1 edit 395ffd83dbSDimitry Andric for (const llvm::StringRef &Item : Allowed) { 405ffd83dbSDimitry Andric auto NoPrefix = Item; 415ffd83dbSDimitry Andric if (!NoPrefix.consume_front(DropPrefix)) 425ffd83dbSDimitry Andric continue; 43fe6060f1SDimitry Andric if (NoPrefix.equals_insensitive(Search)) { 44*0fca6ea1SDimitry Andric if (NoPrefix == Search) 455ffd83dbSDimitry Andric return Item.str(); 465ffd83dbSDimitry Andric MaxEditDistance = 1; 475ffd83dbSDimitry Andric Res = Item; 485ffd83dbSDimitry Andric continue; 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric unsigned Distance = NoPrefix.edit_distance(Search); 515ffd83dbSDimitry Andric if (Distance < MaxEditDistance) { 525ffd83dbSDimitry Andric MaxEditDistance = Distance; 535ffd83dbSDimitry Andric Res = Item; 545ffd83dbSDimitry Andric } 555ffd83dbSDimitry Andric } 565ffd83dbSDimitry Andric if (!Res.empty()) 575ffd83dbSDimitry Andric return Res.str(); 585ffd83dbSDimitry Andric } 59bdd1243dSDimitry Andric return std::nullopt; 605ffd83dbSDimitry Andric } 615ffd83dbSDimitry Andric 62bdd1243dSDimitry Andric std::optional<std::string> 635ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 645ffd83dbSDimitry Andric clang::attr::Kind>::getBestGuess(const VariantValue &Value) { 655ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 665ffd83dbSDimitry Andric #define ATTR(X) "attr::" #X, 675ffd83dbSDimitry Andric #include "clang/Basic/AttrList.inc" 685ffd83dbSDimitry Andric }; 695ffd83dbSDimitry Andric if (Value.isString()) 70bdd1243dSDimitry Andric return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "attr::"); 71bdd1243dSDimitry Andric return std::nullopt; 725ffd83dbSDimitry Andric } 735ffd83dbSDimitry Andric 74bdd1243dSDimitry Andric std::optional<std::string> 755ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 765ffd83dbSDimitry Andric clang::CastKind>::getBestGuess(const VariantValue &Value) { 775ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 785ffd83dbSDimitry Andric #define CAST_OPERATION(Name) "CK_" #Name, 795ffd83dbSDimitry Andric #include "clang/AST/OperationKinds.def" 805ffd83dbSDimitry Andric }; 815ffd83dbSDimitry Andric if (Value.isString()) 82bdd1243dSDimitry Andric return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "CK_"); 83bdd1243dSDimitry Andric return std::nullopt; 845ffd83dbSDimitry Andric } 855ffd83dbSDimitry Andric 86bdd1243dSDimitry Andric std::optional<std::string> 875ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 885ffd83dbSDimitry Andric clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) { 895ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 90e8d8bef9SDimitry Andric #define GEN_CLANG_CLAUSE_CLASS 91e8d8bef9SDimitry Andric #define CLAUSE_CLASS(Enum, Str, Class) #Enum, 92e8d8bef9SDimitry Andric #include "llvm/Frontend/OpenMP/OMP.inc" 935ffd83dbSDimitry Andric }; 945ffd83dbSDimitry Andric if (Value.isString()) 95bdd1243dSDimitry Andric return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "OMPC_"); 96bdd1243dSDimitry Andric return std::nullopt; 975ffd83dbSDimitry Andric } 985ffd83dbSDimitry Andric 99bdd1243dSDimitry Andric std::optional<std::string> 1005ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 1015ffd83dbSDimitry Andric clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) { 1025ffd83dbSDimitry Andric static constexpr llvm::StringRef Allowed[] = { 1035ffd83dbSDimitry Andric #define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 1045ffd83dbSDimitry Andric #define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, 1055ffd83dbSDimitry Andric #include "clang/Basic/TokenKinds.def" 1065ffd83dbSDimitry Andric }; 1075ffd83dbSDimitry Andric if (Value.isString()) 108bdd1243dSDimitry Andric return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "UETT_"); 109bdd1243dSDimitry Andric return std::nullopt; 1105ffd83dbSDimitry Andric } 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags> 1135ffd83dbSDimitry Andric RegexMap[] = { 1145ffd83dbSDimitry Andric {"NoFlags", llvm::Regex::RegexFlags::NoFlags}, 1155ffd83dbSDimitry Andric {"IgnoreCase", llvm::Regex::RegexFlags::IgnoreCase}, 1165ffd83dbSDimitry Andric {"Newline", llvm::Regex::RegexFlags::Newline}, 1175ffd83dbSDimitry Andric {"BasicRegex", llvm::Regex::RegexFlags::BasicRegex}, 1185ffd83dbSDimitry Andric }; 1195ffd83dbSDimitry Andric 120bdd1243dSDimitry Andric static std::optional<llvm::Regex::RegexFlags> 121e8d8bef9SDimitry Andric getRegexFlag(llvm::StringRef Flag) { 1225ffd83dbSDimitry Andric for (const auto &StringFlag : RegexMap) { 1235ffd83dbSDimitry Andric if (Flag == StringFlag.first) 1245ffd83dbSDimitry Andric return StringFlag.second; 1255ffd83dbSDimitry Andric } 126bdd1243dSDimitry Andric return std::nullopt; 1275ffd83dbSDimitry Andric } 1285ffd83dbSDimitry Andric 129bdd1243dSDimitry Andric static std::optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) { 1305ffd83dbSDimitry Andric for (const auto &StringFlag : RegexMap) { 1315ffd83dbSDimitry Andric if (Flag.edit_distance(StringFlag.first) < 3) 1325ffd83dbSDimitry Andric return StringFlag.first; 1335ffd83dbSDimitry Andric } 134bdd1243dSDimitry Andric return std::nullopt; 1355ffd83dbSDimitry Andric } 1365ffd83dbSDimitry Andric 137bdd1243dSDimitry Andric std::optional<llvm::Regex::RegexFlags> 1385ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 1395ffd83dbSDimitry Andric llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) { 140bdd1243dSDimitry Andric std::optional<llvm::Regex::RegexFlags> Flag; 1415ffd83dbSDimitry Andric SmallVector<StringRef, 4> Split; 1425ffd83dbSDimitry Andric Flags.split(Split, '|', -1, false); 1435ffd83dbSDimitry Andric for (StringRef OrFlag : Split) { 144bdd1243dSDimitry Andric if (std::optional<llvm::Regex::RegexFlags> NextFlag = 1455ffd83dbSDimitry Andric getRegexFlag(OrFlag.trim())) 14681ad6265SDimitry Andric Flag = Flag.value_or(llvm::Regex::NoFlags) | *NextFlag; 1475ffd83dbSDimitry Andric else 148bdd1243dSDimitry Andric return std::nullopt; 1495ffd83dbSDimitry Andric } 1505ffd83dbSDimitry Andric return Flag; 1515ffd83dbSDimitry Andric } 1525ffd83dbSDimitry Andric 153bdd1243dSDimitry Andric std::optional<std::string> 1545ffd83dbSDimitry Andric clang::ast_matchers::dynamic::internal::ArgTypeTraits< 1555ffd83dbSDimitry Andric llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) { 1565ffd83dbSDimitry Andric if (!Value.isString()) 157bdd1243dSDimitry Andric return std::nullopt; 1585ffd83dbSDimitry Andric SmallVector<StringRef, 4> Split; 1595ffd83dbSDimitry Andric llvm::StringRef(Value.getString()).split(Split, '|', -1, false); 1605ffd83dbSDimitry Andric for (llvm::StringRef &Flag : Split) { 161bdd1243dSDimitry Andric if (std::optional<llvm::StringRef> BestGuess = 1625ffd83dbSDimitry Andric getCloseRegexMatch(Flag.trim())) 1635ffd83dbSDimitry Andric Flag = *BestGuess; 1645ffd83dbSDimitry Andric else 165bdd1243dSDimitry Andric return std::nullopt; 1665ffd83dbSDimitry Andric } 1675ffd83dbSDimitry Andric if (Split.empty()) 168bdd1243dSDimitry Andric return std::nullopt; 1695ffd83dbSDimitry Andric return llvm::join(Split, " | "); 1705ffd83dbSDimitry Andric } 171