diff options
Diffstat (limited to 'clang/lib/ASTMatchers/Dynamic/VariantValue.cpp')
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/VariantValue.cpp | 457 | 
1 files changed, 457 insertions, 0 deletions
| diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 000000000000..118ca2a41cb1 --- /dev/null +++ b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -0,0 +1,457 @@ +//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Polymorphic value type. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +std::string ArgKind::asString() const { +  switch (getArgKind()) { +  case AK_Matcher: +    return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); +  case AK_Boolean: +    return "boolean"; +  case AK_Double: +    return "double"; +  case AK_Unsigned: +    return "unsigned"; +  case AK_String: +    return "string"; +  } +  llvm_unreachable("unhandled ArgKind"); +} + +bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const { +  if (K != To.K) +    return false; +  if (K != AK_Matcher) { +    if (Specificity) +      *Specificity = 1; +    return true; +  } +  unsigned Distance; +  if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance)) +    return false; + +  if (Specificity) +    *Specificity = 100 - Distance; +  return true; +} + +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, +                                             bool &IsExactMatch) const { +  IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); +  return Matcher.canConvertTo(NodeKind); +} + +llvm::Optional<DynTypedMatcher> +VariantMatcher::MatcherOps::constructVariadicOperator( +    DynTypedMatcher::VariadicOperator Op, +    ArrayRef<VariantMatcher> InnerMatchers) const { +  std::vector<DynTypedMatcher> DynMatchers; +  for (const auto &InnerMatcher : InnerMatchers) { +    // Abort if any of the inner matchers can't be converted to +    // Matcher<T>. +    if (!InnerMatcher.Value) +      return llvm::None; +    llvm::Optional<DynTypedMatcher> Inner = +        InnerMatcher.Value->getTypedMatcher(*this); +    if (!Inner) +      return llvm::None; +    DynMatchers.push_back(*Inner); +  } +  return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers); +} + +VariantMatcher::Payload::~Payload() {} + +class VariantMatcher::SinglePayload : public VariantMatcher::Payload { +public: +  SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} + +  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { +    return Matcher; +  } + +  std::string getTypeAsString() const override { +    return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") +        .str(); +  } + +  llvm::Optional<DynTypedMatcher> +  getTypedMatcher(const MatcherOps &Ops) const override { +    bool Ignore; +    if (Ops.canConstructFrom(Matcher, Ignore)) +      return Matcher; +    return llvm::None; +  } + +  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, +                       unsigned *Specificity) const override { +    return ArgKind(Matcher.getSupportedKind()) +        .isConvertibleTo(Kind, Specificity); +  } + +private: +  const DynTypedMatcher Matcher; +}; + +class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { +public: +  PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn) +      : Matchers(std::move(MatchersIn)) {} + +  ~PolymorphicPayload() override {} + +  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { +    if (Matchers.size() != 1) +      return llvm::Optional<DynTypedMatcher>(); +    return Matchers[0]; +  } + +  std::string getTypeAsString() const override { +    std::string Inner; +    for (size_t i = 0, e = Matchers.size(); i != e; ++i) { +      if (i != 0) +        Inner += "|"; +      Inner += Matchers[i].getSupportedKind().asStringRef(); +    } +    return (Twine("Matcher<") + Inner + ">").str(); +  } + +  llvm::Optional<DynTypedMatcher> +  getTypedMatcher(const MatcherOps &Ops) const override { +    bool FoundIsExact = false; +    const DynTypedMatcher *Found = nullptr; +    int NumFound = 0; +    for (size_t i = 0, e = Matchers.size(); i != e; ++i) { +      bool IsExactMatch; +      if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) { +        if (Found) { +          if (FoundIsExact) { +            assert(!IsExactMatch && "We should not have two exact matches."); +            continue; +          } +        } +        Found = &Matchers[i]; +        FoundIsExact = IsExactMatch; +        ++NumFound; +      } +    } +    // We only succeed if we found exactly one, or if we found an exact match. +    if (Found && (FoundIsExact || NumFound == 1)) +      return *Found; +    return llvm::None; +  } + +  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, +                       unsigned *Specificity) const override { +    unsigned MaxSpecificity = 0; +    for (const DynTypedMatcher &Matcher : Matchers) { +      unsigned ThisSpecificity; +      if (ArgKind(Matcher.getSupportedKind()) +              .isConvertibleTo(Kind, &ThisSpecificity)) { +        MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); +      } +    } +    if (Specificity) +      *Specificity = MaxSpecificity; +    return MaxSpecificity > 0; +  } + +  const std::vector<DynTypedMatcher> Matchers; +}; + +class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { +public: +  VariadicOpPayload(DynTypedMatcher::VariadicOperator Op, +                    std::vector<VariantMatcher> Args) +      : Op(Op), Args(std::move(Args)) {} + +  llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { +    return llvm::Optional<DynTypedMatcher>(); +  } + +  std::string getTypeAsString() const override { +    std::string Inner; +    for (size_t i = 0, e = Args.size(); i != e; ++i) { +      if (i != 0) +        Inner += "&"; +      Inner += Args[i].getTypeAsString(); +    } +    return Inner; +  } + +  llvm::Optional<DynTypedMatcher> +  getTypedMatcher(const MatcherOps &Ops) const override { +    return Ops.constructVariadicOperator(Op, Args); +  } + +  bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, +                       unsigned *Specificity) const override { +    for (const VariantMatcher &Matcher : Args) { +      if (!Matcher.isConvertibleTo(Kind, Specificity)) +        return false; +    } +    return true; +  } + +private: +  const DynTypedMatcher::VariadicOperator Op; +  const std::vector<VariantMatcher> Args; +}; + +VariantMatcher::VariantMatcher() {} + +VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { +  return VariantMatcher(std::make_shared<SinglePayload>(Matcher)); +} + +VariantMatcher +VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { +  return VariantMatcher( +      std::make_shared<PolymorphicPayload>(std::move(Matchers))); +} + +VariantMatcher VariantMatcher::VariadicOperatorMatcher( +    DynTypedMatcher::VariadicOperator Op, +    std::vector<VariantMatcher> Args) { +  return VariantMatcher( +      std::make_shared<VariadicOpPayload>(Op, std::move(Args))); +} + +llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { +  return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>(); +} + +void VariantMatcher::reset() { Value.reset(); } + +std::string VariantMatcher::getTypeAsString() const { +  if (Value) return Value->getTypeAsString(); +  return "<Nothing>"; +} + +VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { +  *this = Other; +} + +VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) { +  setBoolean(Boolean); +} + +VariantValue::VariantValue(double Double) : Type(VT_Nothing) { +  setDouble(Double); +} + +VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { +  setUnsigned(Unsigned); +} + +VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { +  setString(String); +} + +VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { +  setMatcher(Matcher); +} + +VariantValue::~VariantValue() { reset(); } + +VariantValue &VariantValue::operator=(const VariantValue &Other) { +  if (this == &Other) return *this; +  reset(); +  switch (Other.Type) { +  case VT_Boolean: +    setBoolean(Other.getBoolean()); +    break; +  case VT_Double: +    setDouble(Other.getDouble()); +    break; +  case VT_Unsigned: +    setUnsigned(Other.getUnsigned()); +    break; +  case VT_String: +    setString(Other.getString()); +    break; +  case VT_Matcher: +    setMatcher(Other.getMatcher()); +    break; +  case VT_Nothing: +    Type = VT_Nothing; +    break; +  } +  return *this; +} + +void VariantValue::reset() { +  switch (Type) { +  case VT_String: +    delete Value.String; +    break; +  case VT_Matcher: +    delete Value.Matcher; +    break; +  // Cases that do nothing. +  case VT_Boolean: +  case VT_Double: +  case VT_Unsigned: +  case VT_Nothing: +    break; +  } +  Type = VT_Nothing; +} + +bool VariantValue::isBoolean() const { +  return Type == VT_Boolean; +} + +bool VariantValue::getBoolean() const { +  assert(isBoolean()); +  return Value.Boolean; +} + +void VariantValue::setBoolean(bool NewValue) { +  reset(); +  Type = VT_Boolean; +  Value.Boolean = NewValue; +} + +bool VariantValue::isDouble() const { +  return Type == VT_Double; +} + +double VariantValue::getDouble() const { +  assert(isDouble()); +  return Value.Double; +} + +void VariantValue::setDouble(double NewValue) { +  reset(); +  Type = VT_Double; +  Value.Double = NewValue; +} + +bool VariantValue::isUnsigned() const { +  return Type == VT_Unsigned; +} + +unsigned VariantValue::getUnsigned() const { +  assert(isUnsigned()); +  return Value.Unsigned; +} + +void VariantValue::setUnsigned(unsigned NewValue) { +  reset(); +  Type = VT_Unsigned; +  Value.Unsigned = NewValue; +} + +bool VariantValue::isString() const { +  return Type == VT_String; +} + +const std::string &VariantValue::getString() const { +  assert(isString()); +  return *Value.String; +} + +void VariantValue::setString(StringRef NewValue) { +  reset(); +  Type = VT_String; +  Value.String = new std::string(NewValue); +} + +bool VariantValue::isMatcher() const { +  return Type == VT_Matcher; +} + +const VariantMatcher &VariantValue::getMatcher() const { +  assert(isMatcher()); +  return *Value.Matcher; +} + +void VariantValue::setMatcher(const VariantMatcher &NewValue) { +  reset(); +  Type = VT_Matcher; +  Value.Matcher = new VariantMatcher(NewValue); +} + +bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { +  switch (Kind.getArgKind()) { +  case ArgKind::AK_Boolean: +    if (!isBoolean()) +      return false; +    *Specificity = 1; +    return true; + +  case ArgKind::AK_Double: +    if (!isDouble()) +      return false; +    *Specificity = 1; +    return true; + +  case ArgKind::AK_Unsigned: +    if (!isUnsigned()) +      return false; +    *Specificity = 1; +    return true; + +  case ArgKind::AK_String: +    if (!isString()) +      return false; +    *Specificity = 1; +    return true; + +  case ArgKind::AK_Matcher: +    if (!isMatcher()) +      return false; +    return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity); +  } +  llvm_unreachable("Invalid Type"); +} + +bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds, +                                   unsigned *Specificity) const { +  unsigned MaxSpecificity = 0; +  for (const ArgKind& Kind : Kinds) { +    unsigned ThisSpecificity; +    if (!isConvertibleTo(Kind, &ThisSpecificity)) +      continue; +    MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); +  } +  if (Specificity && MaxSpecificity > 0) { +    *Specificity = MaxSpecificity; +  } +  return MaxSpecificity > 0; +} + +std::string VariantValue::getTypeAsString() const { +  switch (Type) { +  case VT_String: return "String"; +  case VT_Matcher: return getMatcher().getTypeAsString(); +  case VT_Boolean: return "Boolean"; +  case VT_Double: return "Double"; +  case VT_Unsigned: return "Unsigned"; +  case VT_Nothing: return "Nothing"; +  } +  llvm_unreachable("Invalid Type"); +} + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang | 
