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