//===--- VariantValue.h - 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.
///
/// Supports all the types required for dynamic Matcher construction.
/// Used by the registry to construct matchers in a generic way.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include <memory>
#include <vector>
namespace clang {
namespace ast_matchers {
namespace dynamic {
/// Kind identifier.
///
/// It supports all types that VariantValue can contain.
class ArgKind {
public:
enum Kind {
AK_Matcher,
AK_Node,
AK_Boolean,
AK_Double,
AK_Unsigned,
AK_String
};
/// Constructor for non-matcher types.
ArgKind(Kind K) : K(K) { assert(K != AK_Matcher); }
/// Constructor for matcher types.
static ArgKind MakeMatcherArg(ASTNodeKind MatcherKind) {
return ArgKind{AK_Matcher, MatcherKind};
}
static ArgKind MakeNodeArg(ASTNodeKind MatcherKind) {
return ArgKind{AK_Node, MatcherKind};
}
Kind getArgKind() const { return K; }
ASTNodeKind getMatcherKind() const {
assert(K == AK_Matcher);
return NodeKind;
}
ASTNodeKind getNodeKind() const {
assert(K == AK_Node);
return NodeKind;
}
/// Determines if this type can be converted to \p To.
///
/// \param To the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
/// conversion.
bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
bool operator<(const ArgKind &Other) const {
if ((K == AK_Matcher && Other.K == AK_Matcher) ||
(K == AK_Node && Other.K == AK_Node))
return NodeKind < Other.NodeKind;
return K < Other.K;
}
/// String representation of the type.
std::string asString() const;
private:
ArgKind(Kind K, ASTNodeKind NK) : K(K), NodeKind(NK) {}
Kind K;
ASTNodeKind NodeKind;
};
using ast_matchers::internal::DynTypedMatcher;
/// A variant matcher object.
///
/// The purpose of this object is to abstract simple and polymorphic matchers
/// into a single object type.
/// Polymorphic matchers might be implemented as a list of all the possible
/// overloads of the matcher. \c VariantMatcher knows how to select the
/// appropriate overload when needed.
/// To get a real matcher object out of a \c VariantMatcher you can do:
/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous
/// to decide which matcher to return. Eg. it contains only a single
/// matcher, or a polymorphic one with only one overload.
/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
/// the underlying matcher(s) can unambiguously return a Matcher<T>.
class VariantMatcher {
/// Methods that depend on T from hasTypedMatcher/getTypedMatcher.
class MatcherOps {
public:
MatcherOps(ASTNodeKind NodeKind) : NodeKind(NodeKind) {}
bool canConstructFrom(const DynTypedMatcher &Matcher,
bool &IsExactMatch) const;
/// Convert \p Matcher the destination type and return it as a new
/// DynTypedMatcher.
DynTypedMatcher convertMatcher(const DynTypedMatcher &Matcher) const;
/// Constructs a variadic typed matcher from \p InnerMatchers.
/// Will try to convert each inner matcher to the destination type and
/// return llvm::None if it fails to do so.
llvm::Optional<DynTypedMatcher>
constructVariadicOperator(DynTypedMatcher::VariadicOperator Op,
ArrayRef<VariantMatcher> InnerMatchers) const;
private:
ASTNodeKind NodeKind;
};
/// Payload interface to be specialized by each matcher type.
///
/// It follows a similar interface as VariantMatcher itself.
class Payload {
public:
virtual ~Payload();
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
virtual llvm::Optional<DynTypedMatcher>
getTypedMatcher(const MatcherOps &Ops) const = 0;
virtual bool isConvertibleTo(ASTNodeKind Kind,
unsigned *Specificity) const = 0;
};
public:
/// A null matcher.
VariantMatcher();
/// Clones the provided matcher.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher);
/// Clones the provided matchers.
///
/// They should be the result of a polymorphic matcher.
static VariantMatcher
PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
/// Creates a 'variadic' operator matcher.
///
/// It will bind to the appropriate type on getTypedMatcher<T>().
static VariantMatcher
VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op,
std::vector<VariantMatcher> Args);
/// Makes the matcher the "null" matcher.
void reset();
/// Whether the matcher is null.
bool isNull() const { return !Value; }
/// Return a single matcher, if there is no ambiguity.
///
/// \returns the matcher, if there is only one matcher. An empty Optional, if
/// the underlying matcher is a polymorphic matcher with more than one
/// representation.
llvm::Optional<DynTypedMatcher> getSingleMatcher() const;
/// Determines if the contained matcher can be converted to
/// \c Matcher<T>.
///
/// For the Single case, it returns true if it can be converted to
/// \c Matcher<T>.
/// For the Polymorphic case, it returns true if one, and only one, of the
/// overloads can be converted to \c Matcher<T>. If there are more than one
/// that can, the result would be ambiguous and false is returned.
template <class T>
bool hasTypedMatcher() const {
return hasTypedMatcher(ASTNodeKind::getFromNodeKind<T>());
}
bool hasTypedMatcher(ASTNodeKind NK) const {
if (!Value) return false;
return Value->getTypedMatcher(MatcherOps(NK)).has_value();
}
/// Determines if the contained matcher can be converted to \p Kind.
///
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
/// conversion.
bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const {
if (Value)
return Value->isConvertibleTo(Kind, Specificity);
return false;
}
/// Return this matcher as a \c Matcher<T>.
///
/// Handles the different types (Single, Polymorphic) accordingly.
/// Asserts that \c hasTypedMatcher<T>() is true.
template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
assert(hasTypedMatcher<T>() && "hasTypedMatcher<T>() == false");
return Value->getTypedMatcher(MatcherOps(ASTNodeKind::getFromNodeKind<T>()))
->template convertTo<T>();
}
DynTypedMatcher getTypedMatcher(ASTNodeKind NK) const {
assert(hasTypedMatcher(NK) && "hasTypedMatcher(NK) == false");
return *Value->getTypedMatcher(MatcherOps(NK));
}
/// String representation of the type of the value.
///
/// If the underlying matcher is a polymorphic one, the string will show all
/// the types.
std::string getTypeAsString() const;
private:
explicit VariantMatcher(std::shared_ptr<Payload> Value)
: Value(std::move(Value)) {}
class SinglePayload;
class PolymorphicPayload;
class VariadicOpPayload;
std::shared_ptr<const Payload> Value;
};
/// Variant value class.
///
/// Basically, a tagged union with value type semantics.
/// It is used by the registry as the return value and argument type for the
/// matcher factory methods.
/// It can be constructed from any of the supported types. It supports
/// copy/assignment.
///
/// Supported types:
/// - \c bool
// - \c double
/// - \c unsigned
/// - \c llvm::StringRef
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
class VariantValue {
public:
VariantValue() : Type(VT_Nothing) {}
VariantValue(const VariantValue &Other);
~VariantValue();
VariantValue &operator=(const VariantValue &Other);
/// Specific constructors for each supported type.
VariantValue(bool Boolean);
VariantValue(double Double);
VariantValue(unsigned Unsigned);
VariantValue(StringRef String);
VariantValue(ASTNodeKind NodeKind);
VariantValue(const VariantMatcher &Matchers);
/// Constructs an \c unsigned value (disambiguation from bool).
VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
/// Returns true iff this is not an empty value.
explicit operator bool() const { return hasValue(); }
bool hasValue() const { return Type != VT_Nothing; }
/// Boolean value functions.
bool isBoolean() const;
bool getBoolean() const;
void setBoolean(bool Boolean);
/// Double value functions.
bool isDouble() const;
double getDouble() const;
void setDouble(double Double);
/// Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
void setUnsigned(unsigned Unsigned);
/// String value functions.
bool isString() const;
const std::string &getString() const;
void setString(StringRef String);
bool isNodeKind() const;
const ASTNodeKind &getNodeKind() const;
void setNodeKind(ASTNodeKind NodeKind);
/// Matcher value functions.
bool isMatcher() const;
const VariantMatcher &getMatcher() const;
void setMatcher(const VariantMatcher &Matcher);
/// Determines if the contained value can be converted to \p Kind.
///
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
/// conversion.
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
/// Determines if the contained value can be converted to any kind
/// in \p Kinds.
///
/// \param Kinds the requested destination types.
///
/// \param Specificity value corresponding to the "specificity" of the
/// conversion. It is the maximum specificity of all the possible
/// conversions.
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
/// String representation of the type of the value.
std::string getTypeAsString() const;
private:
void reset();
/// All supported value types.
enum ValueType {
VT_Nothing,
VT_Boolean,
VT_Double,
VT_Unsigned,
VT_String,
VT_Matcher,
VT_NodeKind
};
/// All supported value types.
union AllValues {
unsigned Unsigned;
double Double;
bool Boolean;
std::string *String;
VariantMatcher *Matcher;
ASTNodeKind *NodeKind;
};
ValueType Type;
AllValues Value;
};
} // end namespace dynamic
} // end namespace ast_matchers
} // end namespace clang
#endif // LLVM_CLANG_ASTMATCHERS_DYNAMIC_VARIANTVALUE_H