1259701Sdim//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ 2259701Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6259701Sdim// 7259701Sdim//===----------------------------------------------------------------------===// 8259701Sdim/// 9259701Sdim/// \file 10341825Sdim/// Polymorphic value type. 11259701Sdim/// 12259701Sdim//===----------------------------------------------------------------------===// 13259701Sdim 14259701Sdim#include "clang/ASTMatchers/Dynamic/VariantValue.h" 15259701Sdim#include "clang/Basic/LLVM.h" 16259701Sdim#include "llvm/ADT/STLExtras.h" 17259701Sdim 18259701Sdimnamespace clang { 19259701Sdimnamespace ast_matchers { 20259701Sdimnamespace dynamic { 21259701Sdim 22280031Sdimstd::string ArgKind::asString() const { 23280031Sdim switch (getArgKind()) { 24280031Sdim case AK_Matcher: 25280031Sdim return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); 26321369Sdim case AK_Boolean: 27321369Sdim return "boolean"; 28321369Sdim case AK_Double: 29321369Sdim return "double"; 30280031Sdim case AK_Unsigned: 31280031Sdim return "unsigned"; 32280031Sdim case AK_String: 33280031Sdim return "string"; 34280031Sdim } 35280031Sdim llvm_unreachable("unhandled ArgKind"); 36280031Sdim} 37280031Sdim 38280031Sdimbool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const { 39280031Sdim if (K != To.K) 40280031Sdim return false; 41280031Sdim if (K != AK_Matcher) { 42280031Sdim if (Specificity) 43280031Sdim *Specificity = 1; 44280031Sdim return true; 45280031Sdim } 46280031Sdim unsigned Distance; 47280031Sdim if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance)) 48280031Sdim return false; 49280031Sdim 50280031Sdim if (Specificity) 51280031Sdim *Specificity = 100 - Distance; 52280031Sdim return true; 53280031Sdim} 54280031Sdim 55280031Sdimbool 56280031SdimVariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, 57280031Sdim bool &IsExactMatch) const { 58280031Sdim IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); 59280031Sdim return Matcher.canConvertTo(NodeKind); 60280031Sdim} 61280031Sdim 62280031Sdimllvm::Optional<DynTypedMatcher> 63280031SdimVariantMatcher::MatcherOps::constructVariadicOperator( 64280031Sdim DynTypedMatcher::VariadicOperator Op, 65280031Sdim ArrayRef<VariantMatcher> InnerMatchers) const { 66280031Sdim std::vector<DynTypedMatcher> DynMatchers; 67280031Sdim for (const auto &InnerMatcher : InnerMatchers) { 68280031Sdim // Abort if any of the inner matchers can't be converted to 69280031Sdim // Matcher<T>. 70280031Sdim if (!InnerMatcher.Value) 71280031Sdim return llvm::None; 72280031Sdim llvm::Optional<DynTypedMatcher> Inner = 73280031Sdim InnerMatcher.Value->getTypedMatcher(*this); 74280031Sdim if (!Inner) 75280031Sdim return llvm::None; 76280031Sdim DynMatchers.push_back(*Inner); 77280031Sdim } 78296417Sdim return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers); 79280031Sdim} 80280031Sdim 81259701SdimVariantMatcher::Payload::~Payload() {} 82259701Sdim 83259701Sdimclass VariantMatcher::SinglePayload : public VariantMatcher::Payload { 84259701Sdimpublic: 85259701Sdim SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} 86259701Sdim 87280031Sdim llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { 88259701Sdim return Matcher; 89259701Sdim } 90259701Sdim 91280031Sdim std::string getTypeAsString() const override { 92259701Sdim return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") 93259701Sdim .str(); 94259701Sdim } 95259701Sdim 96280031Sdim llvm::Optional<DynTypedMatcher> 97280031Sdim getTypedMatcher(const MatcherOps &Ops) const override { 98276479Sdim bool Ignore; 99276479Sdim if (Ops.canConstructFrom(Matcher, Ignore)) 100280031Sdim return Matcher; 101280031Sdim return llvm::None; 102259701Sdim } 103259701Sdim 104280031Sdim bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, 105280031Sdim unsigned *Specificity) const override { 106280031Sdim return ArgKind(Matcher.getSupportedKind()) 107280031Sdim .isConvertibleTo(Kind, Specificity); 108280031Sdim } 109280031Sdim 110259701Sdimprivate: 111259701Sdim const DynTypedMatcher Matcher; 112259701Sdim}; 113259701Sdim 114259701Sdimclass VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { 115259701Sdimpublic: 116276479Sdim PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn) 117276479Sdim : Matchers(std::move(MatchersIn)) {} 118259701Sdim 119280031Sdim ~PolymorphicPayload() override {} 120259701Sdim 121280031Sdim llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { 122259701Sdim if (Matchers.size() != 1) 123259701Sdim return llvm::Optional<DynTypedMatcher>(); 124259701Sdim return Matchers[0]; 125259701Sdim } 126259701Sdim 127280031Sdim std::string getTypeAsString() const override { 128259701Sdim std::string Inner; 129259701Sdim for (size_t i = 0, e = Matchers.size(); i != e; ++i) { 130259701Sdim if (i != 0) 131259701Sdim Inner += "|"; 132259701Sdim Inner += Matchers[i].getSupportedKind().asStringRef(); 133259701Sdim } 134259701Sdim return (Twine("Matcher<") + Inner + ">").str(); 135259701Sdim } 136259701Sdim 137280031Sdim llvm::Optional<DynTypedMatcher> 138280031Sdim getTypedMatcher(const MatcherOps &Ops) const override { 139276479Sdim bool FoundIsExact = false; 140276479Sdim const DynTypedMatcher *Found = nullptr; 141276479Sdim int NumFound = 0; 142259701Sdim for (size_t i = 0, e = Matchers.size(); i != e; ++i) { 143276479Sdim bool IsExactMatch; 144276479Sdim if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) { 145276479Sdim if (Found) { 146276479Sdim if (FoundIsExact) { 147276479Sdim assert(!IsExactMatch && "We should not have two exact matches."); 148276479Sdim continue; 149276479Sdim } 150276479Sdim } 151259701Sdim Found = &Matchers[i]; 152276479Sdim FoundIsExact = IsExactMatch; 153276479Sdim ++NumFound; 154259701Sdim } 155259701Sdim } 156276479Sdim // We only succeed if we found exactly one, or if we found an exact match. 157276479Sdim if (Found && (FoundIsExact || NumFound == 1)) 158280031Sdim return *Found; 159280031Sdim return llvm::None; 160259701Sdim } 161259701Sdim 162280031Sdim bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, 163280031Sdim unsigned *Specificity) const override { 164280031Sdim unsigned MaxSpecificity = 0; 165280031Sdim for (const DynTypedMatcher &Matcher : Matchers) { 166280031Sdim unsigned ThisSpecificity; 167280031Sdim if (ArgKind(Matcher.getSupportedKind()) 168280031Sdim .isConvertibleTo(Kind, &ThisSpecificity)) { 169280031Sdim MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); 170280031Sdim } 171280031Sdim } 172280031Sdim if (Specificity) 173280031Sdim *Specificity = MaxSpecificity; 174280031Sdim return MaxSpecificity > 0; 175280031Sdim } 176280031Sdim 177259701Sdim const std::vector<DynTypedMatcher> Matchers; 178259701Sdim}; 179259701Sdim 180259701Sdimclass VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { 181259701Sdimpublic: 182280031Sdim VariadicOpPayload(DynTypedMatcher::VariadicOperator Op, 183276479Sdim std::vector<VariantMatcher> Args) 184280031Sdim : Op(Op), Args(std::move(Args)) {} 185259701Sdim 186280031Sdim llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { 187259701Sdim return llvm::Optional<DynTypedMatcher>(); 188259701Sdim } 189259701Sdim 190280031Sdim std::string getTypeAsString() const override { 191259701Sdim std::string Inner; 192259701Sdim for (size_t i = 0, e = Args.size(); i != e; ++i) { 193259701Sdim if (i != 0) 194259701Sdim Inner += "&"; 195259701Sdim Inner += Args[i].getTypeAsString(); 196259701Sdim } 197259701Sdim return Inner; 198259701Sdim } 199259701Sdim 200280031Sdim llvm::Optional<DynTypedMatcher> 201280031Sdim getTypedMatcher(const MatcherOps &Ops) const override { 202280031Sdim return Ops.constructVariadicOperator(Op, Args); 203259701Sdim } 204259701Sdim 205280031Sdim bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, 206280031Sdim unsigned *Specificity) const override { 207280031Sdim for (const VariantMatcher &Matcher : Args) { 208280031Sdim if (!Matcher.isConvertibleTo(Kind, Specificity)) 209280031Sdim return false; 210280031Sdim } 211280031Sdim return true; 212280031Sdim } 213280031Sdim 214259701Sdimprivate: 215280031Sdim const DynTypedMatcher::VariadicOperator Op; 216259701Sdim const std::vector<VariantMatcher> Args; 217259701Sdim}; 218259701Sdim 219259701SdimVariantMatcher::VariantMatcher() {} 220259701Sdim 221259701SdimVariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { 222314564Sdim return VariantMatcher(std::make_shared<SinglePayload>(Matcher)); 223259701Sdim} 224259701Sdim 225259701SdimVariantMatcher 226276479SdimVariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { 227314564Sdim return VariantMatcher( 228314564Sdim std::make_shared<PolymorphicPayload>(std::move(Matchers))); 229259701Sdim} 230259701Sdim 231259701SdimVariantMatcher VariantMatcher::VariadicOperatorMatcher( 232280031Sdim DynTypedMatcher::VariadicOperator Op, 233276479Sdim std::vector<VariantMatcher> Args) { 234314564Sdim return VariantMatcher( 235314564Sdim std::make_shared<VariadicOpPayload>(Op, std::move(Args))); 236259701Sdim} 237259701Sdim 238259701Sdimllvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { 239259701Sdim return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>(); 240259701Sdim} 241259701Sdim 242259701Sdimvoid VariantMatcher::reset() { Value.reset(); } 243259701Sdim 244259701Sdimstd::string VariantMatcher::getTypeAsString() const { 245259701Sdim if (Value) return Value->getTypeAsString(); 246259701Sdim return "<Nothing>"; 247259701Sdim} 248259701Sdim 249259701SdimVariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { 250259701Sdim *this = Other; 251259701Sdim} 252259701Sdim 253321369SdimVariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) { 254321369Sdim setBoolean(Boolean); 255321369Sdim} 256321369Sdim 257321369SdimVariantValue::VariantValue(double Double) : Type(VT_Nothing) { 258321369Sdim setDouble(Double); 259321369Sdim} 260321369Sdim 261259701SdimVariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) { 262259701Sdim setUnsigned(Unsigned); 263259701Sdim} 264259701Sdim 265288943SdimVariantValue::VariantValue(StringRef String) : Type(VT_Nothing) { 266259701Sdim setString(String); 267259701Sdim} 268259701Sdim 269259701SdimVariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { 270259701Sdim setMatcher(Matcher); 271259701Sdim} 272259701Sdim 273259701SdimVariantValue::~VariantValue() { reset(); } 274259701Sdim 275259701SdimVariantValue &VariantValue::operator=(const VariantValue &Other) { 276259701Sdim if (this == &Other) return *this; 277259701Sdim reset(); 278259701Sdim switch (Other.Type) { 279321369Sdim case VT_Boolean: 280321369Sdim setBoolean(Other.getBoolean()); 281321369Sdim break; 282321369Sdim case VT_Double: 283321369Sdim setDouble(Other.getDouble()); 284321369Sdim break; 285259701Sdim case VT_Unsigned: 286259701Sdim setUnsigned(Other.getUnsigned()); 287259701Sdim break; 288259701Sdim case VT_String: 289259701Sdim setString(Other.getString()); 290259701Sdim break; 291259701Sdim case VT_Matcher: 292259701Sdim setMatcher(Other.getMatcher()); 293259701Sdim break; 294259701Sdim case VT_Nothing: 295259701Sdim Type = VT_Nothing; 296259701Sdim break; 297259701Sdim } 298259701Sdim return *this; 299259701Sdim} 300259701Sdim 301259701Sdimvoid VariantValue::reset() { 302259701Sdim switch (Type) { 303259701Sdim case VT_String: 304259701Sdim delete Value.String; 305259701Sdim break; 306259701Sdim case VT_Matcher: 307259701Sdim delete Value.Matcher; 308259701Sdim break; 309259701Sdim // Cases that do nothing. 310321369Sdim case VT_Boolean: 311321369Sdim case VT_Double: 312259701Sdim case VT_Unsigned: 313259701Sdim case VT_Nothing: 314259701Sdim break; 315259701Sdim } 316259701Sdim Type = VT_Nothing; 317259701Sdim} 318259701Sdim 319321369Sdimbool VariantValue::isBoolean() const { 320321369Sdim return Type == VT_Boolean; 321321369Sdim} 322321369Sdim 323321369Sdimbool VariantValue::getBoolean() const { 324321369Sdim assert(isBoolean()); 325321369Sdim return Value.Boolean; 326321369Sdim} 327321369Sdim 328321369Sdimvoid VariantValue::setBoolean(bool NewValue) { 329321369Sdim reset(); 330321369Sdim Type = VT_Boolean; 331321369Sdim Value.Boolean = NewValue; 332321369Sdim} 333321369Sdim 334321369Sdimbool VariantValue::isDouble() const { 335321369Sdim return Type == VT_Double; 336321369Sdim} 337321369Sdim 338321369Sdimdouble VariantValue::getDouble() const { 339321369Sdim assert(isDouble()); 340321369Sdim return Value.Double; 341321369Sdim} 342321369Sdim 343321369Sdimvoid VariantValue::setDouble(double NewValue) { 344321369Sdim reset(); 345321369Sdim Type = VT_Double; 346321369Sdim Value.Double = NewValue; 347321369Sdim} 348321369Sdim 349259701Sdimbool VariantValue::isUnsigned() const { 350259701Sdim return Type == VT_Unsigned; 351259701Sdim} 352259701Sdim 353259701Sdimunsigned VariantValue::getUnsigned() const { 354259701Sdim assert(isUnsigned()); 355259701Sdim return Value.Unsigned; 356259701Sdim} 357259701Sdim 358259701Sdimvoid VariantValue::setUnsigned(unsigned NewValue) { 359259701Sdim reset(); 360259701Sdim Type = VT_Unsigned; 361259701Sdim Value.Unsigned = NewValue; 362259701Sdim} 363259701Sdim 364259701Sdimbool VariantValue::isString() const { 365259701Sdim return Type == VT_String; 366259701Sdim} 367259701Sdim 368259701Sdimconst std::string &VariantValue::getString() const { 369259701Sdim assert(isString()); 370259701Sdim return *Value.String; 371259701Sdim} 372259701Sdim 373288943Sdimvoid VariantValue::setString(StringRef NewValue) { 374259701Sdim reset(); 375259701Sdim Type = VT_String; 376259701Sdim Value.String = new std::string(NewValue); 377259701Sdim} 378259701Sdim 379259701Sdimbool VariantValue::isMatcher() const { 380259701Sdim return Type == VT_Matcher; 381259701Sdim} 382259701Sdim 383259701Sdimconst VariantMatcher &VariantValue::getMatcher() const { 384259701Sdim assert(isMatcher()); 385259701Sdim return *Value.Matcher; 386259701Sdim} 387259701Sdim 388259701Sdimvoid VariantValue::setMatcher(const VariantMatcher &NewValue) { 389259701Sdim reset(); 390259701Sdim Type = VT_Matcher; 391259701Sdim Value.Matcher = new VariantMatcher(NewValue); 392259701Sdim} 393259701Sdim 394280031Sdimbool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { 395280031Sdim switch (Kind.getArgKind()) { 396321369Sdim case ArgKind::AK_Boolean: 397321369Sdim if (!isBoolean()) 398321369Sdim return false; 399321369Sdim *Specificity = 1; 400321369Sdim return true; 401321369Sdim 402321369Sdim case ArgKind::AK_Double: 403321369Sdim if (!isDouble()) 404321369Sdim return false; 405321369Sdim *Specificity = 1; 406321369Sdim return true; 407321369Sdim 408280031Sdim case ArgKind::AK_Unsigned: 409280031Sdim if (!isUnsigned()) 410280031Sdim return false; 411280031Sdim *Specificity = 1; 412280031Sdim return true; 413280031Sdim 414280031Sdim case ArgKind::AK_String: 415280031Sdim if (!isString()) 416280031Sdim return false; 417280031Sdim *Specificity = 1; 418280031Sdim return true; 419280031Sdim 420280031Sdim case ArgKind::AK_Matcher: 421280031Sdim if (!isMatcher()) 422280031Sdim return false; 423280031Sdim return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity); 424280031Sdim } 425280031Sdim llvm_unreachable("Invalid Type"); 426280031Sdim} 427280031Sdim 428280031Sdimbool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds, 429280031Sdim unsigned *Specificity) const { 430280031Sdim unsigned MaxSpecificity = 0; 431280031Sdim for (const ArgKind& Kind : Kinds) { 432280031Sdim unsigned ThisSpecificity; 433280031Sdim if (!isConvertibleTo(Kind, &ThisSpecificity)) 434280031Sdim continue; 435280031Sdim MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); 436280031Sdim } 437280031Sdim if (Specificity && MaxSpecificity > 0) { 438280031Sdim *Specificity = MaxSpecificity; 439280031Sdim } 440280031Sdim return MaxSpecificity > 0; 441280031Sdim} 442280031Sdim 443259701Sdimstd::string VariantValue::getTypeAsString() const { 444259701Sdim switch (Type) { 445259701Sdim case VT_String: return "String"; 446259701Sdim case VT_Matcher: return getMatcher().getTypeAsString(); 447321369Sdim case VT_Boolean: return "Boolean"; 448321369Sdim case VT_Double: return "Double"; 449259701Sdim case VT_Unsigned: return "Unsigned"; 450259701Sdim case VT_Nothing: return "Nothing"; 451259701Sdim } 452259701Sdim llvm_unreachable("Invalid Type"); 453259701Sdim} 454259701Sdim 455259701Sdim} // end namespace dynamic 456259701Sdim} // end namespace ast_matchers 457259701Sdim} // end namespace clang 458