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