Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix usage of "override" on initializers of derived classes #363

Merged
merged 11 commits into from
Oct 22, 2024
19 changes: 18 additions & 1 deletion Generator/Sources/SwiftWinRT/Writing/ClassDefinition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,14 @@ fileprivate func writeComposableInitializers(
let propertyName = SecondaryInterfaces.getPropertyName(factoryInterface.bind())

for method in factoryInterface.methods {
// Swift requires "override" on initializers iff the same initializer is defined in the direct base class
let `override` = try base != nil && hasComposableConstructor(classDefinition: base!, paramTypes: method.params.map { try $0.type })
// The last 2 params should be the IInspectable outer and inner pointers
let (params, returnParam) = try projection.getParamBindings(method: method, genericTypeArgs: [], abiKind: .composableFactory)
try writer.writeInit(
documentation: try projection.getDocumentationComment(abiMember: method, classDefinition: classDefinition),
visibility: .public,
override: params.count == 2 && base != nil, // Hack: assume all base classes have a default initializer we are overriding
override: `override`,
params: params.dropLast(2).map { $0.toSwiftParam() }, // Drop inner and outer pointer params
throws: true) { writer in
let output = writer.output
Expand All @@ -319,6 +321,21 @@ fileprivate func writeComposableInitializers(
}
}

fileprivate func hasComposableConstructor(classDefinition: ClassDefinition, paramTypes: [TypeNode]) throws -> Bool {
if classDefinition.fullName == "System.Object" {
return paramTypes.count == 2 // Default composable constructor with Inner and Outer pointers
}

for composableAttribute in try classDefinition.getAttributes(ComposableAttribute.self) {
for composableConstructor in composableAttribute.factory.methods {
guard try composableConstructor.arity == paramTypes.count else { continue }
if try composableConstructor.params.map({ try $0.type }) == paramTypes { return true }
}
}

return false
}

fileprivate func writeDefaultActivatableInitializer(
_ classDefinition: ClassDefinition,
projection: Projection, to writer: SwiftTypeDefinitionWriter) throws {
Expand Down
4 changes: 4 additions & 0 deletions InteropTests/WinRTComponent/Dll/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
cmake_minimum_required(VERSION 3.21.0)
project(WinRTComponentDll LANGUAGES CXX)

if(NOT DEFINED WINRTCOMPONENT_WINMD)
message(FATAL_ERROR "WINRTCOMPONENT_WINMD must be defined")
endif()
Expand All @@ -13,6 +16,7 @@ cmake_path(CONVERT "${WINRTCOMPONENT_WINMD}" TO_NATIVE_PATH_LIST WINRTCOMPONENT_
string(REPLACE "\\" "" WINSDK_VERSION "$ENV{WindowsSDKVersion}")
set(CPPWINRT_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/CppWinRT")
cmake_path(CONVERT "${CPPWINRT_GENERATED_DIR}" TO_NATIVE_PATH_LIST CPPWINRT_GENERATED_DIR_NATIVE)
file(REMOVE_RECURSE "${CPPWINRT_GENERATED_DIR}")
execute_process(
COMMAND "${CPPWINRT_EXE_NATIVE}"
-input "${WINRTCOMPONENT_WINMD_NATIVE}"
Expand Down
6 changes: 6 additions & 0 deletions InteropTests/WinRTComponent/Dll/ShadowingConstructors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "pch.h"

// C++/WinRT struggles with a derived class having a default constructor which delegates to a base class constructor with a parameter.
// So just stub out the exports here as we won't instantiate the classes anyways.
void * __cdecl winrt_make_WinRTComponent_ShadowingConstructorsBase() { return nullptr; }
void * __cdecl winrt_make_WinRTComponent_ShadowingConstructorsDerived() { return nullptr; }
4 changes: 1 addition & 3 deletions InteropTests/WinRTComponent/GenerateProjection.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ function(generate_projection)
endif()

# Delete the previous projection files
execute_process(
COMMAND ${CMAKE_COMMAND} -E remove_directory "${ARG_PROJECTION_DIR}"
COMMAND_ERROR_IS_FATAL ANY)
file(REMOVE_RECURSE "${ARG_PROJECTION_DIR}")

# Generate the projection
cmake_path(CONVERT "${ARG_PROJECTION_JSON}" TO_NATIVE_PATH_LIST PROJECTION_JSON_NATIVE)
Expand Down
3 changes: 2 additions & 1 deletion InteropTests/WinRTComponent/IDL/ManualAsyncOperation.idl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace WinRTComponent
{
runtimeclass ManualAsyncOperation : Windows.Foundation.IAsyncOperation<Int32> {
runtimeclass ManualAsyncOperation : Windows.Foundation.IAsyncOperation<Int32>
{
ManualAsyncOperation(Int32 id);
void Complete(Int32 result);
void CompleteWithError(HRESULT errorCode);
Expand Down
14 changes: 14 additions & 0 deletions InteropTests/WinRTComponent/IDL/ShadowingConstructors.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace WinRTComponent
{
unsealed runtimeclass ShadowingConstructorsBase
{
ShadowingConstructorsBase(Int32 param); // "value" name is reserved (due to generated COM code?)
};

unsealed runtimeclass ShadowingConstructorsDerived : ShadowingConstructorsBase
{
// Regression test for https://github.com/tristanlabelle/swift-winrt/issues/360
ShadowingConstructorsDerived(); // Does not directly shadow
ShadowingConstructorsDerived(Int32 param); // Shadows
};
}
1 change: 1 addition & 0 deletions InteropTests/WinRTComponent/IDL/WinRTComponent.idl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "OverloadedSum.idl"
#include "ReferenceBoxing.idl"
#include "ReturnArgument.idl"
#include "ShadowingConstructors.idl"
#include "Strings.idl"
#include "Structs.idl"
#include "SwiftAttributes.idl"
Expand Down