Files
clang-p2996/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

458 lines
12 KiB
C++

//===--- 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