Summary: Replace variadic operator function pointer with an enum value. Hiding the implementation of the variadic matcher will allow to specialize them for the operation performed. In particular, it will allow for a more efficient allOf() matcher. Reviewers: klimek Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D6293 llvm-svn: 222432
393 lines
10 KiB
C++
393 lines
10 KiB
C++
//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief 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_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, 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(new SinglePayload(Matcher));
|
|
}
|
|
|
|
VariantMatcher
|
|
VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
|
|
return VariantMatcher(new PolymorphicPayload(std::move(Matchers)));
|
|
}
|
|
|
|
VariantMatcher VariantMatcher::VariadicOperatorMatcher(
|
|
DynTypedMatcher::VariadicOperator Op,
|
|
std::vector<VariantMatcher> Args) {
|
|
return VariantMatcher(new 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(unsigned Unsigned) : Type(VT_Nothing) {
|
|
setUnsigned(Unsigned);
|
|
}
|
|
|
|
VariantValue::VariantValue(const std::string &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_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_Unsigned:
|
|
case VT_Nothing:
|
|
break;
|
|
}
|
|
Type = VT_Nothing;
|
|
}
|
|
|
|
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(const std::string &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_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_Unsigned: return "Unsigned";
|
|
case VT_Nothing: return "Nothing";
|
|
}
|
|
llvm_unreachable("Invalid Type");
|
|
}
|
|
|
|
} // end namespace dynamic
|
|
} // end namespace ast_matchers
|
|
} // end namespace clang
|