Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 55 additions & 12 deletions cppwinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2035,13 +2035,39 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
{
for (auto&& [name, info] : interfaces)
{
if (!info.overridable)
if (!info.overridable && !info.is_protected)
{
w.write(", %", name);
}
}
}

static void write_class_override_protected_requires(writer& w, get_interfaces_t const& interfaces)
{
bool first = true;

for (auto&& [name, info] : interfaces)
{
if (info.is_protected)
{
if (first)
{
first = false;
w.write(",\n protected impl::require<D, %", name);
}
else
{
w.write(", %", name);
}
}
}

if (!first)
{
w.write('>');
}
}

static void write_class_override_defaults(writer& w, get_interfaces_t const& interfaces)
{
bool first = true;
Expand Down Expand Up @@ -2073,6 +2099,18 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
}
}

static void write_class_override_friends(writer& w, get_interfaces_t const& interfaces)
{
for (auto&& [name, info] : interfaces)
{
if (info.is_protected)
{
w.write("\n friend impl::consume_t<D, %>;", name);
w.write("\n friend impl::require_one<D, %>;", name);
}
}
}

static void write_call_factory(writer& w, TypeDef const& type, TypeDef const& factory)
{
std::string factory_name;
Expand Down Expand Up @@ -2243,10 +2281,10 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
auto format = R"( template <typename D, typename... Interfaces>
struct %T :
implements<D%, composing, Interfaces...>,
impl::require<D%>,
impl::require<D%>%,
impl::base<D, %%>%
{
using composable = %;
using composable = %;%
protected:
%% };
)";
Expand All @@ -2258,10 +2296,12 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>
type_name,
bind<write_class_override_implements>(interfaces),
bind<write_class_override_requires>(interfaces),
bind<write_class_override_protected_requires>(interfaces),
type_name,
bind<write_class_override_bases>(type),
bind<write_class_override_defaults>(interfaces),
type_name,
bind<write_class_override_friends>(interfaces),
bind<write_class_override_constructors>(type, factories),
bind<write_class_override_usings>(interfaces));
}
Expand Down Expand Up @@ -2326,18 +2366,21 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>

for (auto&& [interface_name, info] : get_interfaces(w, type))
{
if (info.defaulted && !info.base)
if (!info.is_protected && !info.overridable)
{
for (auto&& method : info.type.MethodList())
if (info.defaulted && !info.base)
{
method_usage[get_name(method)].insert(default_interface_name);
for (auto&& method : info.type.MethodList())
{
method_usage[get_name(method)].insert(default_interface_name);
}
}
}
else
{
for (auto&& method : info.type.MethodList())
else
{
method_usage[get_name(method)].insert(interface_name);
for (auto&& method : info.type.MethodList())
{
method_usage[get_name(method)].insert(interface_name);
}
}
}
}
Expand Down Expand Up @@ -2768,7 +2811,7 @@ struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable<T, D, %>

for (auto&& [interface_name, info] : get_interfaces(w, type))
{
if (!info.defaulted || info.base)
if ((!info.defaulted || info.base) && (!info.is_protected && !info.overridable))
{
if (first)
{
Expand Down
41 changes: 36 additions & 5 deletions cppwinrt/component_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,13 +743,13 @@ catch (...) { return winrt::to_hresult(); }
auto format = R"(namespace winrt::@::implementation
{
template <typename D%, typename... I>
struct WINRT_IMPL_EMPTY_BASES %_base : implements<D, @::%%%, %I...>%%%
struct WINRT_IMPL_EMPTY_BASES %_base : implements<D, @::%%%, %I...>%%%%
{
using base_type = %_base;
using class_type = @::%;
using implements_type = typename %_base::implements_type;
using implements_type::implements_type;
%
%%
hstring GetRuntimeClassName() const
{
return L"%.%";
Expand All @@ -764,6 +764,8 @@ catch (...) { return winrt::to_hresult(); }
std::string base_type_argument;
std::string no_module_lock;
std::string external_requires;
std::string external_protected_requires;
std::string friends;

if (base_type)
{
Expand All @@ -774,7 +776,9 @@ catch (...) { return winrt::to_hresult(); }
composable_base_name = w.write_temp("using composable_base = %;", base_type);
auto base_interfaces = get_interfaces(w, base_type);
uint32_t base_interfaces_count{};
uint32_t protected_base_interfaces_count{};
external_requires = ",\n impl::require<D";
external_protected_requires = ",\n protected impl::require<D";

for (auto&&[name, info] : base_interfaces)
{
Expand All @@ -783,9 +787,25 @@ catch (...) { return winrt::to_hresult(); }
continue;
}

++base_interfaces_count;
external_requires += ", ";
external_requires += name;
if (info.is_protected || info.overridable)
{
++protected_base_interfaces_count;
external_protected_requires += ", ";
external_protected_requires += name;

friends += "\n friend impl::consume_t<D, ";
friends += name;
friends += ">;";
friends += "\n friend impl::require_one<D, ";
friends += name;
friends += ">;";
}
else
{
++base_interfaces_count;
external_requires += ", ";
external_requires += name;
}
}

if (base_interfaces_count)
Expand All @@ -796,6 +816,15 @@ catch (...) { return winrt::to_hresult(); }
{
external_requires.clear();
}

if (protected_base_interfaces_count)
{
external_protected_requires += '>';
}
else
{
external_protected_requires.clear();
}
}
else
{
Expand All @@ -816,13 +845,15 @@ catch (...) { return winrt::to_hresult(); }
base_type_argument,
no_module_lock,
external_requires,
external_protected_requires,
bind<write_component_class_base>(type),
bind<write_component_override_defaults>(type),
type_name,
type_namespace,
type_name,
type_name,
composable_base_name,
friends,
type_namespace,
type_name,
bind<write_component_class_override_constructors>(type),
Expand Down
2 changes: 2 additions & 0 deletions cppwinrt/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ namespace cppwinrt
{
TypeDef type;
bool is_default{};
bool is_protected{};
bool defaulted{};
bool overridable{};
bool base{};
Expand Down Expand Up @@ -577,6 +578,7 @@ namespace cppwinrt
auto type = impl.Interface();
auto name = w.write_temp("%", type);
info.is_default = has_attribute(impl, "Windows.Foundation.Metadata", "DefaultAttribute");
info.is_protected = has_attribute(impl, "Windows.Foundation.Metadata", "ProtectedAttribute");
info.defaulted = !base && (defaulted || info.is_default);

{
Expand Down
5 changes: 5 additions & 0 deletions test/old_tests/Composable/Base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ namespace winrt::Composable::implementation
return 42;
}

int32_t Base::ProtectedMethod()
{
return 0xDEADBEEF;
}

hstring Base::Name() const
{
return m_name;
Expand Down
1 change: 1 addition & 0 deletions test/old_tests/Composable/Base.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace winrt::Composable::implementation
hstring OverridableMethod() ;
virtual hstring OverridableVirtualMethod();
int32_t OverridableNoexceptMethod() noexcept;
int32_t ProtectedMethod();

hstring Name() const;

Expand Down
8 changes: 8 additions & 0 deletions test/old_tests/Composable/Composable.idl
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ namespace Composable
HRESULT OverridableVirtualMethod([out, retval] HSTRING* value);
[noexcept2] HRESULT OverridableNoexceptMethod([out, retval] int* value);
};

[version(1.0), uuid(6EA77EAE-56BC-419D-AE70-211C1A631496), exclusiveto(Base)]
interface IBaseProtected : IInspectable
{
HRESULT ProtectedMethod([out, retval] int* value);
};

[version(1.0), uuid(5f3996e1-3cf7-4716-9a3d-11eb5d32caff), exclusiveto(Derived)]
interface IDerived : IInspectable
{
HRESULT CallProtectedMethod([out, retval] int* value);
};

[version(1.0), uuid(56dc2c28-edd1-4fa3-91e5-f63c3db47070), exclusiveto(Derived)]
Expand All @@ -60,6 +67,7 @@ namespace Composable
{
[default] interface IBase;
[overridable] interface Composable.IBaseOverrides;
[protected] interface Composable.IBaseProtected;
};

[composable(Composable.IDerivedFactory, public, 1.0)]
Expand Down
5 changes: 5 additions & 0 deletions test/old_tests/Composable/Derived.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ namespace winrt::Composable::implementation
{
return L"Derived::OverridableVirtualMethod";
}

int32_t Derived::CallProtectedMethod()
{
return ProtectedMethod();
}
}
1 change: 1 addition & 0 deletions test/old_tests/Composable/Derived.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace winrt::Composable::implementation

hstring VirtualMethod() override;
hstring OverridableVirtualMethod() override;
int32_t CallProtectedMethod();
};
}

Expand Down
30 changes: 29 additions & 1 deletion test/old_tests/UnitTests/Composable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace
constexpr auto Base_OverridableMethod{ L"Base::OverridableMethod"sv };
constexpr auto Base_OverridableVirtualMethod{ L"Base::OverridableVirtualMethod"sv };
constexpr auto Base_OverridableNoexceptMethod{ 42 };
constexpr auto Base_ProtectedMethod{ 0xDEADBEEF };

constexpr auto Derived_VirtualMethod{ L"Derived::VirtualMethod"sv };
constexpr auto Derived_OverridableVirtualMethod{ L"Derived::OverridableVirtualMethod"sv };
Expand Down Expand Up @@ -61,12 +62,20 @@ TEST_CASE("Composable.OverriddenBase")
{
return OverriddenBase_OverridableNoexceptMethod;
}

int32_t CallProtectedMethod()
{
return ProtectedMethod();
}
};
auto object = make<OverriddenBase>();

auto object_self = make_self<OverriddenBase>();
auto object = object_self.as<Base>();
REQUIRE(object.VirtualMethod() == Base_VirtualMethod);
REQUIRE(object.CallOverridableMethod() == OverriddenBase_OverridableMethod);
REQUIRE(object.CallOverridableVirtualMethod() == OverriddenBase_OverridableVirtualMethod);
REQUIRE(object.CallOverridableNoexceptMethod() == OverriddenBase_OverridableNoexceptMethod);
REQUIRE(object_self->CallProtectedMethod() == Base_ProtectedMethod);
}
{
const std::wstring OverridableMethodResult = std::wstring(OverriddenBase_OverridableMethod) + L"=>" + Base_OverridableMethod.data();
Expand Down Expand Up @@ -106,6 +115,7 @@ TEST_CASE("Composable.Derived")
REQUIRE(obj.CallOverridableMethod() == Base_OverridableMethod);
REQUIRE(obj.CallOverridableVirtualMethod() == Derived_OverridableVirtualMethod);
REQUIRE(obj.CallOverridableNoexceptMethod() == Base_OverridableNoexceptMethod);
REQUIRE(obj.CallProtectedMethod() == Base_ProtectedMethod);
}

namespace
Expand Down Expand Up @@ -133,6 +143,24 @@ namespace
CallIDerived(obj);
CallDerived(obj);
}

template <typename T, typename = void>
struct has_ProtectedMember : std::false_type { };

template <typename T>
struct has_ProtectedMember<T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::ProtectedMember)>>> : std::true_type { };

// make sure we can't access protected members directly
static_assert(!has_ProtectedMember<Composable::Base>::value);
static_assert(!has_ProtectedMember<Composable::Derived>::value);
static_assert(!has_ProtectedMember<Foo>::value);
static_assert(!has_ProtectedMember<Bar>::value);

// make sure we can't implicitly convert to IBaseProtected
static_assert(!std::is_convertible_v<Composable::Base, Composable::IBaseProtected>);
static_assert(!std::is_convertible_v<Composable::Derived, Composable::IBaseProtected>);
static_assert(!std::is_convertible_v<Foo, Composable::IBaseProtected>);
static_assert(!std::is_convertible_v<Bar, Composable::IBaseProtected>);
}

TEST_CASE("Composable conversions")
Expand Down
4 changes: 4 additions & 0 deletions test/test_component_base/HierarchyA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ namespace winrt::test_component_base::implementation
//test_component_base::IHierarchyA ia = *this;
//assert(a);
}
int HierarchyA::HierarchyA_Protected()
{
return 42;
}
}
1 change: 1 addition & 0 deletions test/test_component_base/HierarchyA.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace winrt::test_component_base::implementation

HierarchyA(hstring const& name);
void HierarchyA_Method();
int HierarchyA_Protected();
};
}
namespace winrt::test_component_base::factory_implementation
Expand Down
4 changes: 4 additions & 0 deletions test/test_component_base/HierarchyB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ namespace winrt::test_component_base::implementation
{
throw hresult_not_implemented();
}
void HierarchyB::HierarchyB_TestInnerProtected()
{
assert(HierarchyA_Protected() == 42);
}
}
1 change: 1 addition & 0 deletions test/test_component_base/HierarchyB.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace winrt::test_component_base::implementation

HierarchyB(hstring const& name);
void HierarchyB_Method();
void HierarchyB_TestInnerProtected();
};
}
namespace winrt::test_component_base::factory_implementation
Expand Down
Loading