clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
360 lines
11 KiB
C++
360 lines
11 KiB
C++
//===--- 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 <memory>
|
|
#include <optional>
|
|
#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 std::nullopt if it fails to do so.
|
|
std::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 std::optional<DynTypedMatcher> getSingleMatcher() const = 0;
|
|
virtual std::string getTypeAsString() const = 0;
|
|
virtual std::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.
|
|
std::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
|