1259701Sdim//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
2259701Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6259701Sdim//
7259701Sdim//===----------------------------------------------------------------------===//
8259701Sdim///
9259701Sdim/// \file
10341825Sdim/// Polymorphic value type.
11259701Sdim///
12259701Sdim//===----------------------------------------------------------------------===//
13259701Sdim
14259701Sdim#include "clang/ASTMatchers/Dynamic/VariantValue.h"
15259701Sdim#include "clang/Basic/LLVM.h"
16259701Sdim#include "llvm/ADT/STLExtras.h"
17259701Sdim
18259701Sdimnamespace clang {
19259701Sdimnamespace ast_matchers {
20259701Sdimnamespace dynamic {
21259701Sdim
22280031Sdimstd::string ArgKind::asString() const {
23280031Sdim  switch (getArgKind()) {
24280031Sdim  case AK_Matcher:
25280031Sdim    return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
26321369Sdim  case AK_Boolean:
27321369Sdim    return "boolean";
28321369Sdim  case AK_Double:
29321369Sdim    return "double";
30280031Sdim  case AK_Unsigned:
31280031Sdim    return "unsigned";
32280031Sdim  case AK_String:
33280031Sdim    return "string";
34280031Sdim  }
35280031Sdim  llvm_unreachable("unhandled ArgKind");
36280031Sdim}
37280031Sdim
38280031Sdimbool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {
39280031Sdim  if (K != To.K)
40280031Sdim    return false;
41280031Sdim  if (K != AK_Matcher) {
42280031Sdim    if (Specificity)
43280031Sdim      *Specificity = 1;
44280031Sdim    return true;
45280031Sdim  }
46280031Sdim  unsigned Distance;
47280031Sdim  if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance))
48280031Sdim    return false;
49280031Sdim
50280031Sdim  if (Specificity)
51280031Sdim    *Specificity = 100 - Distance;
52280031Sdim  return true;
53280031Sdim}
54280031Sdim
55280031Sdimbool
56280031SdimVariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
57280031Sdim                                             bool &IsExactMatch) const {
58280031Sdim  IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind);
59280031Sdim  return Matcher.canConvertTo(NodeKind);
60280031Sdim}
61280031Sdim
62280031Sdimllvm::Optional<DynTypedMatcher>
63280031SdimVariantMatcher::MatcherOps::constructVariadicOperator(
64280031Sdim    DynTypedMatcher::VariadicOperator Op,
65280031Sdim    ArrayRef<VariantMatcher> InnerMatchers) const {
66280031Sdim  std::vector<DynTypedMatcher> DynMatchers;
67280031Sdim  for (const auto &InnerMatcher : InnerMatchers) {
68280031Sdim    // Abort if any of the inner matchers can't be converted to
69280031Sdim    // Matcher<T>.
70280031Sdim    if (!InnerMatcher.Value)
71280031Sdim      return llvm::None;
72280031Sdim    llvm::Optional<DynTypedMatcher> Inner =
73280031Sdim        InnerMatcher.Value->getTypedMatcher(*this);
74280031Sdim    if (!Inner)
75280031Sdim      return llvm::None;
76280031Sdim    DynMatchers.push_back(*Inner);
77280031Sdim  }
78296417Sdim  return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers);
79280031Sdim}
80280031Sdim
81259701SdimVariantMatcher::Payload::~Payload() {}
82259701Sdim
83259701Sdimclass VariantMatcher::SinglePayload : public VariantMatcher::Payload {
84259701Sdimpublic:
85259701Sdim  SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
86259701Sdim
87280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
88259701Sdim    return Matcher;
89259701Sdim  }
90259701Sdim
91280031Sdim  std::string getTypeAsString() const override {
92259701Sdim    return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
93259701Sdim        .str();
94259701Sdim  }
95259701Sdim
96280031Sdim  llvm::Optional<DynTypedMatcher>
97280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
98276479Sdim    bool Ignore;
99276479Sdim    if (Ops.canConstructFrom(Matcher, Ignore))
100280031Sdim      return Matcher;
101280031Sdim    return llvm::None;
102259701Sdim  }
103259701Sdim
104280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
105280031Sdim                       unsigned *Specificity) const override {
106280031Sdim    return ArgKind(Matcher.getSupportedKind())
107280031Sdim        .isConvertibleTo(Kind, Specificity);
108280031Sdim  }
109280031Sdim
110259701Sdimprivate:
111259701Sdim  const DynTypedMatcher Matcher;
112259701Sdim};
113259701Sdim
114259701Sdimclass VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
115259701Sdimpublic:
116276479Sdim  PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
117276479Sdim      : Matchers(std::move(MatchersIn)) {}
118259701Sdim
119280031Sdim  ~PolymorphicPayload() override {}
120259701Sdim
121280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
122259701Sdim    if (Matchers.size() != 1)
123259701Sdim      return llvm::Optional<DynTypedMatcher>();
124259701Sdim    return Matchers[0];
125259701Sdim  }
126259701Sdim
127280031Sdim  std::string getTypeAsString() const override {
128259701Sdim    std::string Inner;
129259701Sdim    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
130259701Sdim      if (i != 0)
131259701Sdim        Inner += "|";
132259701Sdim      Inner += Matchers[i].getSupportedKind().asStringRef();
133259701Sdim    }
134259701Sdim    return (Twine("Matcher<") + Inner + ">").str();
135259701Sdim  }
136259701Sdim
137280031Sdim  llvm::Optional<DynTypedMatcher>
138280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
139276479Sdim    bool FoundIsExact = false;
140276479Sdim    const DynTypedMatcher *Found = nullptr;
141276479Sdim    int NumFound = 0;
142259701Sdim    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
143276479Sdim      bool IsExactMatch;
144276479Sdim      if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {
145276479Sdim        if (Found) {
146276479Sdim          if (FoundIsExact) {
147276479Sdim            assert(!IsExactMatch && "We should not have two exact matches.");
148276479Sdim            continue;
149276479Sdim          }
150276479Sdim        }
151259701Sdim        Found = &Matchers[i];
152276479Sdim        FoundIsExact = IsExactMatch;
153276479Sdim        ++NumFound;
154259701Sdim      }
155259701Sdim    }
156276479Sdim    // We only succeed if we found exactly one, or if we found an exact match.
157276479Sdim    if (Found && (FoundIsExact || NumFound == 1))
158280031Sdim      return *Found;
159280031Sdim    return llvm::None;
160259701Sdim  }
161259701Sdim
162280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
163280031Sdim                       unsigned *Specificity) const override {
164280031Sdim    unsigned MaxSpecificity = 0;
165280031Sdim    for (const DynTypedMatcher &Matcher : Matchers) {
166280031Sdim      unsigned ThisSpecificity;
167280031Sdim      if (ArgKind(Matcher.getSupportedKind())
168280031Sdim              .isConvertibleTo(Kind, &ThisSpecificity)) {
169280031Sdim        MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
170280031Sdim      }
171280031Sdim    }
172280031Sdim    if (Specificity)
173280031Sdim      *Specificity = MaxSpecificity;
174280031Sdim    return MaxSpecificity > 0;
175280031Sdim  }
176280031Sdim
177259701Sdim  const std::vector<DynTypedMatcher> Matchers;
178259701Sdim};
179259701Sdim
180259701Sdimclass VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
181259701Sdimpublic:
182280031Sdim  VariadicOpPayload(DynTypedMatcher::VariadicOperator Op,
183276479Sdim                    std::vector<VariantMatcher> Args)
184280031Sdim      : Op(Op), Args(std::move(Args)) {}
185259701Sdim
186280031Sdim  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
187259701Sdim    return llvm::Optional<DynTypedMatcher>();
188259701Sdim  }
189259701Sdim
190280031Sdim  std::string getTypeAsString() const override {
191259701Sdim    std::string Inner;
192259701Sdim    for (size_t i = 0, e = Args.size(); i != e; ++i) {
193259701Sdim      if (i != 0)
194259701Sdim        Inner += "&";
195259701Sdim      Inner += Args[i].getTypeAsString();
196259701Sdim    }
197259701Sdim    return Inner;
198259701Sdim  }
199259701Sdim
200280031Sdim  llvm::Optional<DynTypedMatcher>
201280031Sdim  getTypedMatcher(const MatcherOps &Ops) const override {
202280031Sdim    return Ops.constructVariadicOperator(Op, Args);
203259701Sdim  }
204259701Sdim
205280031Sdim  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
206280031Sdim                       unsigned *Specificity) const override {
207280031Sdim    for (const VariantMatcher &Matcher : Args) {
208280031Sdim      if (!Matcher.isConvertibleTo(Kind, Specificity))
209280031Sdim        return false;
210280031Sdim    }
211280031Sdim    return true;
212280031Sdim  }
213280031Sdim
214259701Sdimprivate:
215280031Sdim  const DynTypedMatcher::VariadicOperator Op;
216259701Sdim  const std::vector<VariantMatcher> Args;
217259701Sdim};
218259701Sdim
219259701SdimVariantMatcher::VariantMatcher() {}
220259701Sdim
221259701SdimVariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
222314564Sdim  return VariantMatcher(std::make_shared<SinglePayload>(Matcher));
223259701Sdim}
224259701Sdim
225259701SdimVariantMatcher
226276479SdimVariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
227314564Sdim  return VariantMatcher(
228314564Sdim      std::make_shared<PolymorphicPayload>(std::move(Matchers)));
229259701Sdim}
230259701Sdim
231259701SdimVariantMatcher VariantMatcher::VariadicOperatorMatcher(
232280031Sdim    DynTypedMatcher::VariadicOperator Op,
233276479Sdim    std::vector<VariantMatcher> Args) {
234314564Sdim  return VariantMatcher(
235314564Sdim      std::make_shared<VariadicOpPayload>(Op, std::move(Args)));
236259701Sdim}
237259701Sdim
238259701Sdimllvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
239259701Sdim  return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
240259701Sdim}
241259701Sdim
242259701Sdimvoid VariantMatcher::reset() { Value.reset(); }
243259701Sdim
244259701Sdimstd::string VariantMatcher::getTypeAsString() const {
245259701Sdim  if (Value) return Value->getTypeAsString();
246259701Sdim  return "<Nothing>";
247259701Sdim}
248259701Sdim
249259701SdimVariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
250259701Sdim  *this = Other;
251259701Sdim}
252259701Sdim
253321369SdimVariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
254321369Sdim  setBoolean(Boolean);
255321369Sdim}
256321369Sdim
257321369SdimVariantValue::VariantValue(double Double) : Type(VT_Nothing) {
258321369Sdim  setDouble(Double);
259321369Sdim}
260321369Sdim
261259701SdimVariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
262259701Sdim  setUnsigned(Unsigned);
263259701Sdim}
264259701Sdim
265288943SdimVariantValue::VariantValue(StringRef String) : Type(VT_Nothing) {
266259701Sdim  setString(String);
267259701Sdim}
268259701Sdim
269259701SdimVariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {
270259701Sdim  setMatcher(Matcher);
271259701Sdim}
272259701Sdim
273259701SdimVariantValue::~VariantValue() { reset(); }
274259701Sdim
275259701SdimVariantValue &VariantValue::operator=(const VariantValue &Other) {
276259701Sdim  if (this == &Other) return *this;
277259701Sdim  reset();
278259701Sdim  switch (Other.Type) {
279321369Sdim  case VT_Boolean:
280321369Sdim    setBoolean(Other.getBoolean());
281321369Sdim    break;
282321369Sdim  case VT_Double:
283321369Sdim    setDouble(Other.getDouble());
284321369Sdim    break;
285259701Sdim  case VT_Unsigned:
286259701Sdim    setUnsigned(Other.getUnsigned());
287259701Sdim    break;
288259701Sdim  case VT_String:
289259701Sdim    setString(Other.getString());
290259701Sdim    break;
291259701Sdim  case VT_Matcher:
292259701Sdim    setMatcher(Other.getMatcher());
293259701Sdim    break;
294259701Sdim  case VT_Nothing:
295259701Sdim    Type = VT_Nothing;
296259701Sdim    break;
297259701Sdim  }
298259701Sdim  return *this;
299259701Sdim}
300259701Sdim
301259701Sdimvoid VariantValue::reset() {
302259701Sdim  switch (Type) {
303259701Sdim  case VT_String:
304259701Sdim    delete Value.String;
305259701Sdim    break;
306259701Sdim  case VT_Matcher:
307259701Sdim    delete Value.Matcher;
308259701Sdim    break;
309259701Sdim  // Cases that do nothing.
310321369Sdim  case VT_Boolean:
311321369Sdim  case VT_Double:
312259701Sdim  case VT_Unsigned:
313259701Sdim  case VT_Nothing:
314259701Sdim    break;
315259701Sdim  }
316259701Sdim  Type = VT_Nothing;
317259701Sdim}
318259701Sdim
319321369Sdimbool VariantValue::isBoolean() const {
320321369Sdim  return Type == VT_Boolean;
321321369Sdim}
322321369Sdim
323321369Sdimbool VariantValue::getBoolean() const {
324321369Sdim  assert(isBoolean());
325321369Sdim  return Value.Boolean;
326321369Sdim}
327321369Sdim
328321369Sdimvoid VariantValue::setBoolean(bool NewValue) {
329321369Sdim  reset();
330321369Sdim  Type = VT_Boolean;
331321369Sdim  Value.Boolean = NewValue;
332321369Sdim}
333321369Sdim
334321369Sdimbool VariantValue::isDouble() const {
335321369Sdim  return Type == VT_Double;
336321369Sdim}
337321369Sdim
338321369Sdimdouble VariantValue::getDouble() const {
339321369Sdim  assert(isDouble());
340321369Sdim  return Value.Double;
341321369Sdim}
342321369Sdim
343321369Sdimvoid VariantValue::setDouble(double NewValue) {
344321369Sdim  reset();
345321369Sdim  Type = VT_Double;
346321369Sdim  Value.Double = NewValue;
347321369Sdim}
348321369Sdim
349259701Sdimbool VariantValue::isUnsigned() const {
350259701Sdim  return Type == VT_Unsigned;
351259701Sdim}
352259701Sdim
353259701Sdimunsigned VariantValue::getUnsigned() const {
354259701Sdim  assert(isUnsigned());
355259701Sdim  return Value.Unsigned;
356259701Sdim}
357259701Sdim
358259701Sdimvoid VariantValue::setUnsigned(unsigned NewValue) {
359259701Sdim  reset();
360259701Sdim  Type = VT_Unsigned;
361259701Sdim  Value.Unsigned = NewValue;
362259701Sdim}
363259701Sdim
364259701Sdimbool VariantValue::isString() const {
365259701Sdim  return Type == VT_String;
366259701Sdim}
367259701Sdim
368259701Sdimconst std::string &VariantValue::getString() const {
369259701Sdim  assert(isString());
370259701Sdim  return *Value.String;
371259701Sdim}
372259701Sdim
373288943Sdimvoid VariantValue::setString(StringRef NewValue) {
374259701Sdim  reset();
375259701Sdim  Type = VT_String;
376259701Sdim  Value.String = new std::string(NewValue);
377259701Sdim}
378259701Sdim
379259701Sdimbool VariantValue::isMatcher() const {
380259701Sdim  return Type == VT_Matcher;
381259701Sdim}
382259701Sdim
383259701Sdimconst VariantMatcher &VariantValue::getMatcher() const {
384259701Sdim  assert(isMatcher());
385259701Sdim  return *Value.Matcher;
386259701Sdim}
387259701Sdim
388259701Sdimvoid VariantValue::setMatcher(const VariantMatcher &NewValue) {
389259701Sdim  reset();
390259701Sdim  Type = VT_Matcher;
391259701Sdim  Value.Matcher = new VariantMatcher(NewValue);
392259701Sdim}
393259701Sdim
394280031Sdimbool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
395280031Sdim  switch (Kind.getArgKind()) {
396321369Sdim  case ArgKind::AK_Boolean:
397321369Sdim    if (!isBoolean())
398321369Sdim      return false;
399321369Sdim    *Specificity = 1;
400321369Sdim    return true;
401321369Sdim
402321369Sdim  case ArgKind::AK_Double:
403321369Sdim    if (!isDouble())
404321369Sdim      return false;
405321369Sdim    *Specificity = 1;
406321369Sdim    return true;
407321369Sdim
408280031Sdim  case ArgKind::AK_Unsigned:
409280031Sdim    if (!isUnsigned())
410280031Sdim      return false;
411280031Sdim    *Specificity = 1;
412280031Sdim    return true;
413280031Sdim
414280031Sdim  case ArgKind::AK_String:
415280031Sdim    if (!isString())
416280031Sdim      return false;
417280031Sdim    *Specificity = 1;
418280031Sdim    return true;
419280031Sdim
420280031Sdim  case ArgKind::AK_Matcher:
421280031Sdim    if (!isMatcher())
422280031Sdim      return false;
423280031Sdim    return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity);
424280031Sdim  }
425280031Sdim  llvm_unreachable("Invalid Type");
426280031Sdim}
427280031Sdim
428280031Sdimbool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds,
429280031Sdim                                   unsigned *Specificity) const {
430280031Sdim  unsigned MaxSpecificity = 0;
431280031Sdim  for (const ArgKind& Kind : Kinds) {
432280031Sdim    unsigned ThisSpecificity;
433280031Sdim    if (!isConvertibleTo(Kind, &ThisSpecificity))
434280031Sdim      continue;
435280031Sdim    MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);
436280031Sdim  }
437280031Sdim  if (Specificity && MaxSpecificity > 0) {
438280031Sdim    *Specificity = MaxSpecificity;
439280031Sdim  }
440280031Sdim  return MaxSpecificity > 0;
441280031Sdim}
442280031Sdim
443259701Sdimstd::string VariantValue::getTypeAsString() const {
444259701Sdim  switch (Type) {
445259701Sdim  case VT_String: return "String";
446259701Sdim  case VT_Matcher: return getMatcher().getTypeAsString();
447321369Sdim  case VT_Boolean: return "Boolean";
448321369Sdim  case VT_Double: return "Double";
449259701Sdim  case VT_Unsigned: return "Unsigned";
450259701Sdim  case VT_Nothing: return "Nothing";
451259701Sdim  }
452259701Sdim  llvm_unreachable("Invalid Type");
453259701Sdim}
454259701Sdim
455259701Sdim} // end namespace dynamic
456259701Sdim} // end namespace ast_matchers
457259701Sdim} // end namespace clang
458