| // Copyright 2025 The Abseil Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "absl/base/casts.h" | |
| #include <type_traits> | |
| #include <utility> | |
| #include "gtest/gtest.h" | |
| #include "absl/base/options.h" | |
| namespace { | |
| struct BaseForImplicitCast { | |
| explicit BaseForImplicitCast(int value) : x(value) {} | |
| BaseForImplicitCast(const BaseForImplicitCast& other) = delete; | |
| BaseForImplicitCast& operator=(const BaseForImplicitCast& other) = delete; | |
| int x; | |
| }; | |
| struct DerivedForImplicitCast : BaseForImplicitCast { | |
| explicit DerivedForImplicitCast(int value) : BaseForImplicitCast(value) {} | |
| }; | |
| static_assert(std::is_same_v<decltype(absl::implicit_cast<BaseForImplicitCast&>( | |
| std::declval<DerivedForImplicitCast&>())), | |
| BaseForImplicitCast&>); | |
| static_assert( | |
| std::is_same_v<decltype(absl::implicit_cast<const BaseForImplicitCast&>( | |
| std::declval<DerivedForImplicitCast>())), | |
| const BaseForImplicitCast&>); | |
| TEST(ImplicitCastTest, LValueReference) { | |
| DerivedForImplicitCast derived(5); | |
| EXPECT_EQ(&absl::implicit_cast<BaseForImplicitCast&>(derived), &derived); | |
| EXPECT_EQ(&absl::implicit_cast<const BaseForImplicitCast&>(derived), | |
| &derived); | |
| } | |
| TEST(ImplicitCastTest, RValueReference) { | |
| DerivedForImplicitCast derived(5); | |
| BaseForImplicitCast&& base = | |
| absl::implicit_cast<BaseForImplicitCast&&>(std::move(derived)); | |
| EXPECT_EQ(&base, &derived); | |
| const DerivedForImplicitCast cderived(6); | |
| const BaseForImplicitCast&& cbase = | |
| absl::implicit_cast<const BaseForImplicitCast&&>(std::move(cderived)); | |
| EXPECT_EQ(&cbase, &cderived); | |
| } | |
| class BaseForDownCast { | |
| public: | |
| virtual ~BaseForDownCast() = default; | |
| }; | |
| class DerivedForDownCast : public BaseForDownCast {}; | |
| class Derived2ForDownCast : public BaseForDownCast {}; | |
| TEST(DownCastTest, Pointer) { | |
| DerivedForDownCast derived; | |
| BaseForDownCast* const base_ptr = &derived; | |
| // Tests casting a BaseForDownCast* to a DerivedForDownCast*. | |
| EXPECT_EQ(&derived, absl::down_cast<DerivedForDownCast*>(base_ptr)); | |
| // Tests casting a const BaseForDownCast* to a const DerivedForDownCast*. | |
| const BaseForDownCast* const_base_ptr = base_ptr; | |
| EXPECT_EQ(&derived, | |
| absl::down_cast<const DerivedForDownCast*>(const_base_ptr)); | |
| // Tests casting a BaseForDownCast* to a const DerivedForDownCast*. | |
| EXPECT_EQ(&derived, absl::down_cast<const DerivedForDownCast*>(base_ptr)); | |
| // Tests casting a BaseForDownCast* to a BaseForDownCast* (an identity cast). | |
| EXPECT_EQ(base_ptr, absl::down_cast<BaseForDownCast*>(base_ptr)); | |
| // Tests down casting NULL. | |
| EXPECT_EQ(nullptr, | |
| (absl::down_cast<DerivedForDownCast*, BaseForDownCast>(nullptr))); | |
| // Tests a bad downcast. We have to disguise the badness just enough | |
| // that the compiler doesn't warn about it at compile time. | |
| BaseForDownCast* base2 = new BaseForDownCast(); | |
| #if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1)) | |
| EXPECT_DEATH(static_cast<void>(absl::down_cast<DerivedForDownCast*>(base2)), | |
| ".*down cast from .*BaseForDownCast.* to " | |
| ".*DerivedForDownCast.* failed.*"); | |
| #endif | |
| delete base2; | |
| } | |
| TEST(DownCastTest, Reference) { | |
| DerivedForDownCast derived; | |
| BaseForDownCast& base_ref = derived; | |
| // Tests casting a BaseForDownCast& to a DerivedForDownCast&. | |
| // NOLINTNEXTLINE(runtime/casting) | |
| EXPECT_EQ(&derived, &absl::down_cast<DerivedForDownCast&>(base_ref)); | |
| // Tests casting a const BaseForDownCast& to a const DerivedForDownCast&. | |
| const BaseForDownCast& const_base_ref = base_ref; | |
| // NOLINTNEXTLINE(runtime/casting) | |
| EXPECT_EQ(&derived, | |
| &absl::down_cast<const DerivedForDownCast&>(const_base_ref)); | |
| // Tests casting a BaseForDownCast& to a const DerivedForDownCast&. | |
| // NOLINTNEXTLINE(runtime/casting) | |
| EXPECT_EQ(&derived, &absl::down_cast<const DerivedForDownCast&>(base_ref)); | |
| // Tests casting a BaseForDownCast& to a BaseForDownCast& (an identity cast). | |
| // NOLINTNEXTLINE(runtime/casting) | |
| EXPECT_EQ(&base_ref, &absl::down_cast<BaseForDownCast&>(base_ref)); | |
| // Tests a bad downcast. We have to disguise the badness just enough | |
| // that the compiler doesn't warn about it at compile time. | |
| BaseForDownCast& base2 = *new BaseForDownCast(); | |
| #if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1)) | |
| EXPECT_DEATH(static_cast<void>(absl::down_cast<DerivedForDownCast&>(base2)), | |
| ".*down cast from .*BaseForDownCast.* to " | |
| ".*DerivedForDownCast.* failed.*"); | |
| #endif | |
| delete &base2; | |
| } | |
| TEST(DownCastTest, ErrorMessage) { | |
| DerivedForDownCast derived; | |
| BaseForDownCast& base = derived; | |
| (void)base; | |
| #if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1)) | |
| EXPECT_DEATH(static_cast<void>(absl::down_cast<Derived2ForDownCast&>(base)), | |
| ".*down cast from .*DerivedForDownCast.* to " | |
| ".*Derived2ForDownCast.* failed.*"); | |
| #endif | |
| } | |
| } // namespace |