From f7ddbbcd8aba2ac3fe77f2bdc2e21df7255e2a9a Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 18:02:22 +0530 Subject: [PATCH 1/3] fix: erased-target-known-return with 'void'. --- README.md | 8 +++----- .../src/ReflectedCallUnknownReturn.cpp | 6 ++---- .../src/CxxMirrorTests/CxxMirrorObjectTest.cpp | 15 +++++++-------- .../rtl/dispatch/aware_return_n_target.h | 2 +- .../rtl/dispatch/aware_return_n_target_const.h | 2 +- .../rtl/dispatch/method_lambda.h | 2 +- .../rtl/rtl_method_erased_target.h | 9 +++++---- 7 files changed, 20 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 58871b56..3b19850a 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,12 @@ RTL’s reflective calls are comparable to `std::function` for fully type-erased ## A Quick Preview: Reflection That Looks and Feels Like C++ -First, create an instance of `CxxMirror` – +First, create an instance of `rtl::CxxMirror` – ```c++ auto cxx_mirror = rtl::CxxMirror({ /* ...register all types here... */ }); ``` The `cxx_mirror` object provides access to the runtime reflection system. It enables querying, introspection, and instantiation of registered types without requiring compile-time type knowledge at the call site. -It can reside in any translation unit. To make it globally accessible and ensure it is initialized only when needed, a singleton interface can be used – +It can reside in any translation unit. To make it globally accessible and ensure it is initialized only when needed, a singleton access interface can be used – ```c++ // MyReflection.h namespace rtl { class CxxMirror; } // Forward declaration, no includes here! @@ -82,9 +82,7 @@ rtl::CxxMirror& cxx::mirror() { return cxx_mirror; } ``` -`cxx_mirror` is a immutable, stack-allocated, value-type object and is safe to copy. -However, when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror()`) can unintentionally violate the singleton semantics. -To prevent this, the `rtl::CxxMirror`'s copy constructor is restricted to avoid such unintended duplication. +`cxx_mirror` is an immutable, stack-allocated, value-type object and is safe to copy, but when used as a singleton (as shown above), implicit copies (e.g., `auto mirror = cxx::mirror();`) can unintentionally violate the singleton semantics, so `rtl::CxxMirror` restricts such copy construction. ### RTL in action: diff --git a/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp index b6204f79..83277116 100644 --- a/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp +++ b/RTLBenchmarkApp/src/ReflectedCallUnknownReturn.cpp @@ -91,16 +91,14 @@ namespace return method; }(); - //TODO: make return-type 'void' work here, fix compile error. - // rtl::method - static rtl::method ErasedTargetAwareReturn_SendMessage = []() + static rtl::method ErasedTargetAwareReturn_SendMessage = []() { std::optional optMethod = class_Node.getMethod("sendMessage"); if (!optMethod) { std::cerr << "[3] error: method 'Node::sendMessage' not found.\n"; std::abort(); } - auto method = optMethod->targetT<>().argsT().returnT(); + auto method = optMethod->targetT<>().argsT().returnT(); if (!method) { std::cerr << "[3] error: invalid method caller.\n"; std::abort(); diff --git a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp index 1b013ec7..710507f6 100644 --- a/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp +++ b/RTLTestRunApp/src/CxxMirrorTests/CxxMirrorObjectTest.cpp @@ -103,22 +103,21 @@ namespace rtl_tests // Lookup push_back method and call it multiple times with different values. std::optional oPushBack = classVectorInt->getMethod("push_back"); ASSERT_TRUE(oPushBack); - - // TODO: specialize caller for known 'void' return type. - // due to std::optional, compiler error for now - - // rtl::method pushBack = oPushBack->targetT().argsT().returnT(); - rtl::method pushBack = oPushBack->targetT().argsT().returnT(); + rtl::method pushBack = oPushBack->targetT().argsT().returnT(); EXPECT_TRUE(pushBack); { auto [err, ret] = pushBack(robj)(intArr0[0]); - EXPECT_TRUE(err == rtl::error::None); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); } { auto [err, ret] = pushBack(robj)(intArr0[1]); - EXPECT_TRUE(err == rtl::error::None); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); } { auto [err, ret] = pushBack(robj)(intArr0[2]); - EXPECT_TRUE(err == rtl::error::None); + EXPECT_EQ(err, rtl::error::None); + EXPECT_EQ(ret, std::nullopt); } } diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h index 2e259559..9ee6c86d 100644 --- a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h +++ b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target.h @@ -28,7 +28,7 @@ namespace rtl::dispatch if constexpr (std::is_void_v) { (const_cast(target).*mptr)(std::forward(params)...); - return std::make_pair(error::None, std::optional()); + return std::make_pair(error::None, std::optional()); } else { diff --git a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h index 8af27eae..3874f3a4 100644 --- a/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h +++ b/ReflectionTemplateLib/rtl/dispatch/aware_return_n_target_const.h @@ -27,7 +27,7 @@ namespace rtl::dispatch if constexpr (std::is_void_v) { (target.*mptr)(std::forward(params)...); - return std::make_pair(error::None, std::optional()); + return std::make_pair(error::None, std::optional()); } else { diff --git a/ReflectionTemplateLib/rtl/dispatch/method_lambda.h b/ReflectionTemplateLib/rtl/dispatch/method_lambda.h index 0181a03b..a019517c 100644 --- a/ReflectionTemplateLib/rtl/dispatch/method_lambda.h +++ b/ReflectionTemplateLib/rtl/dispatch/method_lambda.h @@ -46,7 +46,7 @@ namespace rtl::dispatch { using if_ref_t = std::conditional_t, std::remove_reference_t*, known_t>; - using if_void_t = std::conditional_t, void*, if_ref_t>; + using if_void_t = std::conditional_t, std::nullptr_t, if_ref_t>; using return_t = std::pair>; diff --git a/ReflectionTemplateLib/rtl/rtl_method_erased_target.h b/ReflectionTemplateLib/rtl/rtl_method_erased_target.h index 8d84316c..26f3a843 100644 --- a/ReflectionTemplateLib/rtl/rtl_method_erased_target.h +++ b/ReflectionTemplateLib/rtl/rtl_method_erased_target.h @@ -15,11 +15,12 @@ namespace rtl { - // TODO: Needs to be well tested, special case return-type 'void' (which does not returns std::nullopt for now) template requires (!std::is_same_v) struct method { - using hopper_t = dispatch::forward_call>, const RObject&, signature_t...>; + using cond_ret_t = std::conditional_t, std::nullptr_t, return_t>; + + using hopper_t = dispatch::forward_call>, const RObject&, signature_t...>; struct invoker { @@ -30,7 +31,7 @@ namespace rtl template requires (sizeof...(args_t) == sizeof...(signature_t)) [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] - constexpr std::pair> operator()(args_t&&...params) const noexcept + constexpr std::pair> operator()(args_t&&...params) const noexcept { if (init_err != error::None) [[unlikely]] { return { init_err, std::nullopt }; @@ -53,7 +54,7 @@ namespace rtl template [[nodiscard]] [[gnu::hot]] [[gnu::flatten]] - constexpr std::pair> operator()(args_t&&...params) const noexcept + constexpr std::pair> operator()(args_t&&...params) const noexcept { if (init_err != error::None) [[unlikely]] { return { init_err, std::nullopt }; From 9bf3fcbc5c8305d8cd3103a0aa2ce0af3ba59464 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 18:35:46 +0530 Subject: [PATCH 2/3] test: erased-target, 'void' return, const-method. --- CxxTestProps/inc/Animal.h | 4 +- CxxTestProps/src/Animal.cpp | 6 +++ .../src/AnimalRegistration.cpp | 7 +++- CxxTestUtils/inc/TestUtilsAnimal.h | 2 + CxxTestUtils/src/TestUtilsAnimal.cpp | 15 ++++++++ .../ConstMethodOverloadTests.cpp | 38 +++++++++++++++++++ 6 files changed, 70 insertions(+), 2 deletions(-) diff --git a/CxxTestProps/inc/Animal.h b/CxxTestProps/inc/Animal.h index 36db6fd1..685509e2 100644 --- a/CxxTestProps/inc/Animal.h +++ b/CxxTestProps/inc/Animal.h @@ -5,7 +5,7 @@ class Animal { - std::string m_name; + mutable std::string m_name; std::string m_familyName; static std::string m_zooKeeper; @@ -37,6 +37,8 @@ class Animal void setAnimalName(const std::string& pName); + void setAnimalName(const std::string& pName) const; + static std::string updateZooKeeper(std::string& pZooKeeper); static std::string updateZooKeeper(std::string&& pZooKeeper); diff --git a/CxxTestProps/src/Animal.cpp b/CxxTestProps/src/Animal.cpp index f85b8e0d..2456338c 100644 --- a/CxxTestProps/src/Animal.cpp +++ b/CxxTestProps/src/Animal.cpp @@ -105,6 +105,12 @@ void Animal::setAnimalName(const std::string& pName) } +void Animal::setAnimalName(const std::string& pName) const +{ + m_name = pName + "__args_const_lvalue_ref_method_const..."; +} + + std::string Animal::updateZooKeeper(std::string& pZooKeeper) { m_zooKeeper = pZooKeeper + "__args_non_const_lvalue_ref..."; diff --git a/CxxTestRegistration/src/AnimalRegistration.cpp b/CxxTestRegistration/src/AnimalRegistration.cpp index fc1060be..99eb56d6 100644 --- a/CxxTestRegistration/src/AnimalRegistration.cpp +++ b/CxxTestRegistration/src/AnimalRegistration.cpp @@ -37,7 +37,12 @@ namespace test_mirror fns.push_back(rtl::type().member() .method(animal::str_setAnimalName) .build(&Animal::setAnimalName)); - + + // Overloaded const-method, taking const-ref as argument. + fns.push_back(rtl::type().member() + .methodConst(animal::str_setAnimalName) + .build(&Animal::setAnimalName)); + // Static method, taking const-ref as argument. fns.push_back(rtl::type().member() .methodStatic(animal::str_updateZooKeeper) diff --git a/CxxTestUtils/inc/TestUtilsAnimal.h b/CxxTestUtils/inc/TestUtilsAnimal.h index fb943e83..cab364e2 100644 --- a/CxxTestUtils/inc/TestUtilsAnimal.h +++ b/CxxTestUtils/inc/TestUtilsAnimal.h @@ -36,6 +36,8 @@ namespace test_utils static const bool test_method_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance); + static const bool test_method_const_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance); + static const bool test_method_setAnimalName_non_const_lvalue_ref_args(const rtl::RObject& pInstance); template diff --git a/CxxTestUtils/src/TestUtilsAnimal.cpp b/CxxTestUtils/src/TestUtilsAnimal.cpp index c79ba3ce..36c8e0c9 100644 --- a/CxxTestUtils/src/TestUtilsAnimal.cpp +++ b/CxxTestUtils/src/TestUtilsAnimal.cpp @@ -78,3 +78,18 @@ const bool test_utils::animal::test_method_setAnimalName_non_const_lvalue_ref_ar } return false; } + + +const bool test_utils::animal::test_method_const_setAnimalName_const_lvalue_ref_args(const rtl::RObject& pInstance) +{ + if (pInstance.canViewAs()) + { + const Animal animal; + auto nameStr = std::string(NAME); + animal.setAnimalName(nameStr); + + const Animal& rAnimal = pInstance.view()->get(); + return (animal == rAnimal); + } + return false; +} \ No newline at end of file diff --git a/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp b/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp index 2bb1e8b5..6d5da6fb 100644 --- a/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp +++ b/RTLTestRunApp/src/FunctionalityTests/ConstMethodOverloadTests.cpp @@ -3,6 +3,7 @@ #include #include "TestMirrorProvider.h" +#include "TestUtilsAnimal.h" #include "TestUtilsPerson.h" #include "TestUtilsBook.h" @@ -246,4 +247,41 @@ namespace rtl_tests EXPECT_TRUE(person::assert_zero_instance_count()); ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); } + + + TEST(ConstMethodOverload, erased_target_known_return_void) + { + { + // Retrieve the metadata for the "Animal" class. + optional classAnimal = cxx::mirror().getRecord(animal::class_); + ASSERT_TRUE(classAnimal); + + // Create an instance of the "Animal" class. + auto [err0, animal] = classAnimal->ctorT()(alloc::Heap); + EXPECT_TRUE(err0 == error::None); + ASSERT_FALSE(animal.isEmpty()); + + // Retrieve the "setAnimalName" method. + optional oSetAnimalName = classAnimal->getMethod(animal::str_setAnimalName); + ASSERT_TRUE(oSetAnimalName); + // Verify that the method has the correct signature for a const L-value reference. + EXPECT_TRUE((oSetAnimalName->hasSignature())); + + auto setAnimalName = oSetAnimalName->targetT().argsT().returnT(); + EXPECT_TRUE(setAnimalName); + + // Invoke the method with a const L-value reference. + auto [err1, ret1] = setAnimalName(std::cref(animal))(animal::NAME); + + EXPECT_EQ(err1, error::None); + EXPECT_EQ(ret1, std::nullopt); + + // Validate the behavior of the method. + EXPECT_TRUE(animal::test_method_const_setAnimalName_const_lvalue_ref_args(animal)); + } + + // Ensure that all instances are cleaned up. + EXPECT_TRUE(animal::assert_zero_instance_count()); + ASSERT_TRUE(rtl::getRtlManagedHeapInstanceCount() == 0); + } } \ No newline at end of file From 93623ecd91c5f78933359c2e4555f137b419ec48 Mon Sep 17 00:00:00 2001 From: neeraj31285 Date: Sun, 18 Jan 2026 18:44:29 +0530 Subject: [PATCH 3/3] codecov: test props and utils exclusion. --- .codecov.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index 2b6e77a9..bd061d04 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -12,6 +12,7 @@ comment: behavior: default ignore: - - "demo/**" + - "CxxTestProps/**" + - "CxxTestUtils/**" - "RTLBenchmarkApp/**" - "ReflectionTemplateLib/rtl/detail/src/RObjectConverters_string.cpp" \ No newline at end of file