493 lines · cpp
1//===--- VariantValue.cpp - Polymorphic value type --------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// Polymorphic value type.11///12//===----------------------------------------------------------------------===//13 14#include "clang/ASTMatchers/Dynamic/VariantValue.h"15#include "clang/Basic/LLVM.h"16#include <optional>17 18namespace clang {19namespace ast_matchers {20namespace dynamic {21 22std::string ArgKind::asString() const {23 switch (getArgKind()) {24 case AK_Matcher:25 return (Twine("Matcher<") + NodeKind.asStringRef() + ">").str();26 case AK_Node:27 return NodeKind.asStringRef().str();28 case AK_Boolean:29 return "boolean";30 case AK_Double:31 return "double";32 case AK_Unsigned:33 return "unsigned";34 case AK_String:35 return "string";36 }37 llvm_unreachable("unhandled ArgKind");38}39 40bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const {41 if (K != To.K)42 return false;43 if (K != AK_Matcher && K != AK_Node) {44 if (Specificity)45 *Specificity = 1;46 return true;47 }48 unsigned Distance;49 if (!NodeKind.isBaseOf(To.NodeKind, &Distance))50 return false;51 52 if (Specificity)53 *Specificity = 100 - Distance;54 return true;55}56 57bool58VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,59 bool &IsExactMatch) const {60 IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind);61 return Matcher.canConvertTo(NodeKind);62}63 64DynTypedMatcher VariantMatcher::MatcherOps::convertMatcher(65 const DynTypedMatcher &Matcher) const {66 return Matcher.dynCastTo(NodeKind);67}68 69std::optional<DynTypedMatcher>70VariantMatcher::MatcherOps::constructVariadicOperator(71 DynTypedMatcher::VariadicOperator Op,72 ArrayRef<VariantMatcher> InnerMatchers) const {73 std::vector<DynTypedMatcher> DynMatchers;74 for (const auto &InnerMatcher : InnerMatchers) {75 // Abort if any of the inner matchers can't be converted to76 // Matcher<T>.77 if (!InnerMatcher.Value)78 return std::nullopt;79 std::optional<DynTypedMatcher> Inner =80 InnerMatcher.Value->getTypedMatcher(*this);81 if (!Inner)82 return std::nullopt;83 DynMatchers.push_back(*Inner);84 }85 return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers);86}87 88VariantMatcher::Payload::~Payload() {}89 90class VariantMatcher::SinglePayload : public VariantMatcher::Payload {91public:92 SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}93 94 std::optional<DynTypedMatcher> getSingleMatcher() const override {95 return Matcher;96 }97 98 std::string getTypeAsString() const override {99 return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")100 .str();101 }102 103 std::optional<DynTypedMatcher>104 getTypedMatcher(const MatcherOps &Ops) const override {105 bool Ignore;106 if (Ops.canConstructFrom(Matcher, Ignore))107 return Matcher;108 return std::nullopt;109 }110 111 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {112 return ArgKind::MakeMatcherArg(Matcher.getSupportedKind())113 .isConvertibleTo(ArgKind::MakeMatcherArg(Kind), Specificity);114 }115 116private:117 const DynTypedMatcher Matcher;118};119 120class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {121public:122 PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)123 : Matchers(std::move(MatchersIn)) {}124 125 ~PolymorphicPayload() override {}126 127 std::optional<DynTypedMatcher> getSingleMatcher() const override {128 if (Matchers.size() != 1)129 return std::nullopt;130 return Matchers[0];131 }132 133 std::string getTypeAsString() const override {134 std::string Inner;135 for (size_t i = 0, e = Matchers.size(); i != e; ++i) {136 if (i != 0)137 Inner += "|";138 Inner += Matchers[i].getSupportedKind().asStringRef();139 }140 return (Twine("Matcher<") + Inner + ">").str();141 }142 143 std::optional<DynTypedMatcher>144 getTypedMatcher(const MatcherOps &Ops) const override {145 bool FoundIsExact = false;146 const DynTypedMatcher *Found = nullptr;147 int NumFound = 0;148 for (size_t i = 0, e = Matchers.size(); i != e; ++i) {149 bool IsExactMatch;150 if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {151 if (Found) {152 if (FoundIsExact) {153 assert(!IsExactMatch && "We should not have two exact matches.");154 continue;155 }156 }157 Found = &Matchers[i];158 FoundIsExact = IsExactMatch;159 ++NumFound;160 }161 }162 // We only succeed if we found exactly one, or if we found an exact match.163 if (Found && (FoundIsExact || NumFound == 1))164 return *Found;165 return std::nullopt;166 }167 168 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {169 unsigned MaxSpecificity = 0;170 for (const DynTypedMatcher &Matcher : Matchers) {171 unsigned ThisSpecificity;172 if (ArgKind::MakeMatcherArg(Matcher.getSupportedKind())173 .isConvertibleTo(ArgKind::MakeMatcherArg(Kind),174 &ThisSpecificity)) {175 MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);176 }177 }178 if (Specificity)179 *Specificity = MaxSpecificity;180 return MaxSpecificity > 0;181 }182 183 const std::vector<DynTypedMatcher> Matchers;184};185 186class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {187public:188 VariadicOpPayload(DynTypedMatcher::VariadicOperator Op,189 std::vector<VariantMatcher> Args)190 : Op(Op), Args(std::move(Args)) {}191 192 std::optional<DynTypedMatcher> getSingleMatcher() const override {193 return std::nullopt;194 }195 196 std::string getTypeAsString() const override {197 std::string Inner;198 for (size_t i = 0, e = Args.size(); i != e; ++i) {199 if (i != 0)200 Inner += "&";201 Inner += Args[i].getTypeAsString();202 }203 return Inner;204 }205 206 std::optional<DynTypedMatcher>207 getTypedMatcher(const MatcherOps &Ops) const override {208 return Ops.constructVariadicOperator(Op, Args);209 }210 211 bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {212 for (const VariantMatcher &Matcher : Args) {213 if (!Matcher.isConvertibleTo(Kind, Specificity))214 return false;215 }216 return true;217 }218 219private:220 const DynTypedMatcher::VariadicOperator Op;221 const std::vector<VariantMatcher> Args;222};223 224VariantMatcher::VariantMatcher() {}225 226VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {227 return VariantMatcher(std::make_shared<SinglePayload>(Matcher));228}229 230VariantMatcher231VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {232 return VariantMatcher(233 std::make_shared<PolymorphicPayload>(std::move(Matchers)));234}235 236VariantMatcher VariantMatcher::VariadicOperatorMatcher(237 DynTypedMatcher::VariadicOperator Op,238 std::vector<VariantMatcher> Args) {239 return VariantMatcher(240 std::make_shared<VariadicOpPayload>(Op, std::move(Args)));241}242 243std::optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {244 return Value ? Value->getSingleMatcher() : std::optional<DynTypedMatcher>();245}246 247void VariantMatcher::reset() { Value.reset(); }248 249std::string VariantMatcher::getTypeAsString() const {250 if (Value) return Value->getTypeAsString();251 return "<Nothing>";252}253 254VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {255 *this = Other;256}257 258VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {259 setBoolean(Boolean);260}261 262VariantValue::VariantValue(double Double) : Type(VT_Nothing) {263 setDouble(Double);264}265 266VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {267 setUnsigned(Unsigned);268}269 270VariantValue::VariantValue(StringRef String) : Type(VT_Nothing) {271 setString(String);272}273 274VariantValue::VariantValue(ASTNodeKind NodeKind) : Type(VT_Nothing) {275 setNodeKind(NodeKind);276}277 278VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) {279 setMatcher(Matcher);280}281 282VariantValue::~VariantValue() { reset(); }283 284VariantValue &VariantValue::operator=(const VariantValue &Other) {285 if (this == &Other) return *this;286 reset();287 switch (Other.Type) {288 case VT_Boolean:289 setBoolean(Other.getBoolean());290 break;291 case VT_Double:292 setDouble(Other.getDouble());293 break;294 case VT_Unsigned:295 setUnsigned(Other.getUnsigned());296 break;297 case VT_String:298 setString(Other.getString());299 break;300 case VT_NodeKind:301 setNodeKind(Other.getNodeKind());302 break;303 case VT_Matcher:304 setMatcher(Other.getMatcher());305 break;306 case VT_Nothing:307 Type = VT_Nothing;308 break;309 }310 return *this;311}312 313void VariantValue::reset() {314 switch (Type) {315 case VT_String:316 delete Value.String;317 break;318 case VT_Matcher:319 delete Value.Matcher;320 break;321 case VT_NodeKind:322 delete Value.NodeKind;323 break;324 // Cases that do nothing.325 case VT_Boolean:326 case VT_Double:327 case VT_Unsigned:328 case VT_Nothing:329 break;330 }331 Type = VT_Nothing;332}333 334bool VariantValue::isBoolean() const {335 return Type == VT_Boolean;336}337 338bool VariantValue::getBoolean() const {339 assert(isBoolean());340 return Value.Boolean;341}342 343void VariantValue::setBoolean(bool NewValue) {344 reset();345 Type = VT_Boolean;346 Value.Boolean = NewValue;347}348 349bool VariantValue::isDouble() const {350 return Type == VT_Double;351}352 353double VariantValue::getDouble() const {354 assert(isDouble());355 return Value.Double;356}357 358void VariantValue::setDouble(double NewValue) {359 reset();360 Type = VT_Double;361 Value.Double = NewValue;362}363 364bool VariantValue::isUnsigned() const {365 return Type == VT_Unsigned;366}367 368unsigned VariantValue::getUnsigned() const {369 assert(isUnsigned());370 return Value.Unsigned;371}372 373void VariantValue::setUnsigned(unsigned NewValue) {374 reset();375 Type = VT_Unsigned;376 Value.Unsigned = NewValue;377}378 379bool VariantValue::isString() const {380 return Type == VT_String;381}382 383const std::string &VariantValue::getString() const {384 assert(isString());385 return *Value.String;386}387 388void VariantValue::setString(StringRef NewValue) {389 reset();390 Type = VT_String;391 Value.String = new std::string(NewValue);392}393 394bool VariantValue::isNodeKind() const { return Type == VT_NodeKind; }395 396const ASTNodeKind &VariantValue::getNodeKind() const {397 assert(isNodeKind());398 return *Value.NodeKind;399}400 401void VariantValue::setNodeKind(ASTNodeKind NewValue) {402 reset();403 Type = VT_NodeKind;404 Value.NodeKind = new ASTNodeKind(NewValue);405}406 407bool VariantValue::isMatcher() const {408 return Type == VT_Matcher;409}410 411const VariantMatcher &VariantValue::getMatcher() const {412 assert(isMatcher());413 return *Value.Matcher;414}415 416void VariantValue::setMatcher(const VariantMatcher &NewValue) {417 reset();418 Type = VT_Matcher;419 Value.Matcher = new VariantMatcher(NewValue);420}421 422bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {423 switch (Kind.getArgKind()) {424 case ArgKind::AK_Boolean:425 if (!isBoolean())426 return false;427 *Specificity = 1;428 return true;429 430 case ArgKind::AK_Double:431 if (!isDouble())432 return false;433 *Specificity = 1;434 return true;435 436 case ArgKind::AK_Unsigned:437 if (!isUnsigned())438 return false;439 *Specificity = 1;440 return true;441 442 case ArgKind::AK_String:443 if (!isString())444 return false;445 *Specificity = 1;446 return true;447 448 case ArgKind::AK_Node:449 if (!isNodeKind())450 return false;451 return getMatcher().isConvertibleTo(Kind.getNodeKind(), Specificity);452 453 case ArgKind::AK_Matcher:454 if (!isMatcher())455 return false;456 return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity);457 }458 llvm_unreachable("Invalid Type");459}460 461bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds,462 unsigned *Specificity) const {463 unsigned MaxSpecificity = 0;464 for (const ArgKind& Kind : Kinds) {465 unsigned ThisSpecificity;466 if (!isConvertibleTo(Kind, &ThisSpecificity))467 continue;468 MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity);469 }470 if (Specificity && MaxSpecificity > 0) {471 *Specificity = MaxSpecificity;472 }473 return MaxSpecificity > 0;474}475 476std::string VariantValue::getTypeAsString() const {477 switch (Type) {478 case VT_String: return "String";479 case VT_Matcher: return getMatcher().getTypeAsString();480 case VT_Boolean: return "Boolean";481 case VT_Double: return "Double";482 case VT_Unsigned: return "Unsigned";483 case VT_NodeKind:484 return getNodeKind().asStringRef().str();485 case VT_Nothing: return "Nothing";486 }487 llvm_unreachable("Invalid Type");488}489 490} // end namespace dynamic491} // end namespace ast_matchers492} // end namespace clang493