186 lines · cpp
1//===- TypeSwitchTest.cpp - TypeSwitch unit tests -------------------------===//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#include "llvm/ADT/TypeSwitch.h"10#include "gtest/gtest.h"11 12using namespace llvm;13 14namespace {15/// Utility classes to setup casting functionality.16struct Base {17 enum Kind { DerivedA, DerivedB, DerivedC, DerivedD, DerivedE };18 Kind kind;19};20template <Base::Kind DerivedKind> struct DerivedImpl : Base {21 DerivedImpl() : Base{DerivedKind} {}22 static bool classof(const Base *base) { return base->kind == DerivedKind; }23};24struct DerivedA : public DerivedImpl<Base::DerivedA> {};25struct DerivedB : public DerivedImpl<Base::DerivedB> {};26struct DerivedC : public DerivedImpl<Base::DerivedC> {};27struct DerivedD : public DerivedImpl<Base::DerivedD> {};28struct DerivedE : public DerivedImpl<Base::DerivedE> {};29} // end anonymous namespace30 31TEST(TypeSwitchTest, CaseResult) {32 auto translate = [](auto value) {33 return TypeSwitch<Base *, int>(&value)34 .Case<DerivedA>([](DerivedA *) { return 0; })35 .Case([](DerivedB *) { return 1; })36 .Case([](DerivedC *) { return 2; })37 .Default([](Base *) { return -1; });38 };39 EXPECT_EQ(0, translate(DerivedA()));40 EXPECT_EQ(1, translate(DerivedB()));41 EXPECT_EQ(2, translate(DerivedC()));42 EXPECT_EQ(-1, translate(DerivedD()));43}44 45TEST(TypeSwitchTest, CasesResult) {46 auto translate = [](auto value) {47 return TypeSwitch<Base *, int>(&value)48 .Case<DerivedA, DerivedB, DerivedD>([](auto *) { return 0; })49 .Case([](DerivedC *) { return 1; })50 .Default(-1);51 };52 EXPECT_EQ(0, translate(DerivedA()));53 EXPECT_EQ(0, translate(DerivedB()));54 EXPECT_EQ(1, translate(DerivedC()));55 EXPECT_EQ(0, translate(DerivedD()));56 EXPECT_EQ(-1, translate(DerivedE()));57}58 59TEST(TypeSwitchTest, CaseVoid) {60 auto translate = [](auto value) {61 int result = -2;62 TypeSwitch<Base *>(&value)63 .Case([&](DerivedA *) { result = 0; })64 .Case([&](DerivedB *) { result = 1; })65 .Case([&](DerivedC *) { result = 2; })66 .Default([&](Base *) { result = -1; });67 return result;68 };69 EXPECT_EQ(0, translate(DerivedA()));70 EXPECT_EQ(1, translate(DerivedB()));71 EXPECT_EQ(2, translate(DerivedC()));72 EXPECT_EQ(-1, translate(DerivedD()));73}74 75TEST(TypeSwitchTest, CasesVoid) {76 auto translate = [](auto value) {77 int result = -1;78 TypeSwitch<Base *>(&value)79 .Case<DerivedA, DerivedB, DerivedD>([&](auto *) { result = 0; })80 .Case([&](DerivedC *) { result = 1; });81 return result;82 };83 EXPECT_EQ(0, translate(DerivedA()));84 EXPECT_EQ(0, translate(DerivedB()));85 EXPECT_EQ(1, translate(DerivedC()));86 EXPECT_EQ(0, translate(DerivedD()));87 EXPECT_EQ(-1, translate(DerivedE()));88}89 90TEST(TypeSwitchTest, CaseOptional) {91 auto translate = [](auto value) {92 return TypeSwitch<Base *, std::optional<int>>(&value)93 .Case([](DerivedA *) { return 0; })94 .Case([](DerivedC *) { return std::nullopt; })95 .Default([](Base *) { return -1; });96 };97 EXPECT_EQ(0, translate(DerivedA()));98 EXPECT_EQ(std::nullopt, translate(DerivedC()));99 EXPECT_EQ(-1, translate(DerivedD()));100 EXPECT_EQ(std::nullopt,101 (TypeSwitch<Base *, std::optional<int>>(nullptr).Default(102 [](Base *) { return std::nullopt; })));103}104 105TEST(TypeSwitchTest, CasesOptional) {106 auto translate = [](auto value) {107 return TypeSwitch<Base *, std::optional<int>>(&value)108 .Case<DerivedB, DerivedC>([](auto *) { return std::nullopt; })109 .Case([](DerivedA *) { return 0; })110 .Default([](Base *) { return -1; });111 };112 EXPECT_EQ(0, translate(DerivedA()));113 EXPECT_EQ(std::nullopt, translate(DerivedB()));114 EXPECT_EQ(std::nullopt, translate(DerivedC()));115 EXPECT_EQ(-1, translate(DerivedD()));116}117 118TEST(TypeSwitchTest, DefaultUnreachableWithValue) {119 auto translate = [](auto value) {120 return TypeSwitch<Base *, int>(&value)121 .Case([](DerivedA *) { return 0; })122 .DefaultUnreachable("Unhandled type");123 };124 EXPECT_EQ(0, translate(DerivedA()));125 126#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)127 EXPECT_DEATH((void)translate(DerivedD()), "Unhandled type");128#endif129}130 131TEST(TypeSwitchTest, DefaultUnreachableWithVoid) {132 auto translate = [](auto value) {133 int result = -1;134 TypeSwitch<Base *>(&value)135 .Case([&result](DerivedA *) { result = 0; })136 .DefaultUnreachable("Unhandled type");137 return result;138 };139 EXPECT_EQ(0, translate(DerivedA()));140 141#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)142 EXPECT_DEATH((void)translate(DerivedD()), "Unhandled type");143#endif144}145 146TEST(TypeSwitchTest, DefaultNullopt) {147 auto translate = [](auto value) {148 return TypeSwitch<Base *, std::optional<int>>(&value)149 .Case([](DerivedA *) { return 0; })150 .Default(std::nullopt);151 };152 EXPECT_EQ(0, translate(DerivedA()));153 EXPECT_EQ(std::nullopt, translate(DerivedD()));154}155 156TEST(TypeSwitchTest, DefaultNullptr) {157 float foo = 0.0f;158 auto translate = [&](auto value) {159 return TypeSwitch<Base *, float *>(&value)160 .Case([&](DerivedA *) { return &foo; })161 .Default(nullptr);162 };163 EXPECT_EQ(&foo, translate(DerivedA()));164 EXPECT_EQ(nullptr, translate(DerivedD()));165}166 167TEST(TypeSwitchTest, DefaultNullptrForPointerLike) {168 struct Value {169 void *ptr;170 Value(const Value &other) = default;171 Value(std::nullptr_t) : ptr(nullptr) {}172 Value() : Value(nullptr) {}173 };174 175 float foo = 0.0f;176 Value fooVal;177 fooVal.ptr = &foo;178 auto translate = [&](auto value) {179 return TypeSwitch<Base *, Value>(&value)180 .Case([&](DerivedA *) { return fooVal; })181 .Default(nullptr);182 };183 EXPECT_EQ(&foo, translate(DerivedA()).ptr);184 EXPECT_EQ(nullptr, translate(DerivedD()).ptr);185}186