Skip to content

Commit 55273ee

Browse files
authored
Merge pull request #6613 from Youssef1313/issues/2937
Generate native ctor only when a ctor with required signature exists in base types
2 parents 2ff49c8 + a3f8e4a commit 55273ee

File tree

2 files changed

+59
-15
lines changed

2 files changed

+59
-15
lines changed

src/SourceGenerators/Uno.UI.SourceGenerators/NativeCtor/NativeCtorsGenerator.cs

+34-15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.CodeAnalysis;
66
using Microsoft.CodeAnalysis.CSharp;
77
using Uno.UI.SourceGenerators.Helpers;
8+
using System.Diagnostics;
89

910
#if NETFRAMEWORK
1011
using Uno.SourceGeneration;
@@ -40,7 +41,7 @@ private class SerializationMethodsGenerator : SymbolVisitor
4041
private readonly INamedTypeSymbol? _intPtrSymbol;
4142
private readonly INamedTypeSymbol? _jniHandleOwnershipSymbol;
4243
private readonly INamedTypeSymbol?[]? _javaCtorParams;
43-
private readonly INamedTypeSymbol? _panelSymbol;
44+
4445
private const string BaseClassFormat =
4546
@"// <auto-generated>
4647
// *************************************************************
@@ -99,7 +100,6 @@ public SerializationMethodsGenerator(GeneratorExecutionContext context)
99100
_androidViewSymbol = context.Compilation.GetTypeByMetadataName("Android.Views.View");
100101
_intPtrSymbol = context.Compilation.GetTypeByMetadataName("System.IntPtr");
101102
_jniHandleOwnershipSymbol = context.Compilation.GetTypeByMetadataName("Android.Runtime.JniHandleOwnership");
102-
_panelSymbol = context.Compilation.GetTypeByMetadataName("Windows.UI.Xaml.Controls.Panel");
103103
_javaCtorParams = new[] { _intPtrSymbol, _jniHandleOwnershipSymbol };
104104
}
105105

@@ -140,12 +140,10 @@ private void ProcessType(INamedTypeSymbol typeSymbol)
140140

141141
if (isiOSView || ismacOSView)
142142
{
143-
var nativeCtor = typeSymbol
144-
.GetMethods()
145-
.Where(m => m.MethodKind == MethodKind.Constructor && SymbolEqualityComparer.Default.Equals(m.Parameters.FirstOrDefault()?.Type, _intPtrSymbol))
146-
.FirstOrDefault();
143+
Func<IMethodSymbol, bool> predicate = m => !m.Parameters.IsDefaultOrEmpty && SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, _intPtrSymbol);
144+
var nativeCtor = GetNativeCtor(typeSymbol, predicate, considerAllBaseTypes: false);
147145

148-
if (nativeCtor == null)
146+
if (nativeCtor == null && GetNativeCtor(typeSymbol.BaseType, predicate, considerAllBaseTypes: true) != null)
149147
{
150148
_context.AddSource(
151149
HashBuilder.BuildIDFromSymbol(typeSymbol),
@@ -162,15 +160,10 @@ private void ProcessType(INamedTypeSymbol typeSymbol)
162160

163161
if (isAndroidView)
164162
{
163+
Func<IMethodSymbol, bool> predicate = m => m.Parameters.Select(p => p.Type).SequenceEqual(_javaCtorParams ?? Array.Empty<ITypeSymbol?>());
164+
var nativeCtor = GetNativeCtor(typeSymbol, predicate, considerAllBaseTypes: false);
165165

166-
var nativeCtor = typeSymbol
167-
.GetMethods()
168-
.Where(m =>
169-
m.MethodKind == MethodKind.Constructor
170-
&& m.Parameters.Select(p => p.Type).SequenceEqual(_javaCtorParams ?? Array.Empty<ITypeSymbol?>()))
171-
.FirstOrDefault();
172-
173-
if (nativeCtor == null)
166+
if (nativeCtor == null && GetNativeCtor(typeSymbol.BaseType, predicate, considerAllBaseTypes: true) != null)
174167
{
175168
_context.AddSource(
176169
HashBuilder.BuildIDFromSymbol(typeSymbol),
@@ -184,6 +177,32 @@ private void ProcessType(INamedTypeSymbol typeSymbol)
184177
);
185178
}
186179
}
180+
181+
static IMethodSymbol? GetNativeCtor(INamedTypeSymbol? type, Func<IMethodSymbol, bool> predicate, bool considerAllBaseTypes)
182+
{
183+
// Consider:
184+
// Type A -> Type B -> Type C
185+
// HasCtor NoCtor NoCtor
186+
// We want to generate the ctor for both Type B and Type C
187+
// But since the generator doesn't guarantee Type B is getting processed first,
188+
// We need to check the inheritance hierarchy.
189+
// However, assume Type B wasn't declared in source, we can't generate the ctor for it.
190+
// Consequently, Type C shouldn't generate source as well.
191+
if (type is null)
192+
{
193+
return null;
194+
}
195+
196+
var ctor = type.GetMembers(WellKnownMemberNames.InstanceConstructorName).Cast<IMethodSymbol>().FirstOrDefault(predicate);
197+
if (ctor != null || !considerAllBaseTypes || !type.Locations.Any(l => l.IsInSource))
198+
{
199+
return ctor;
200+
}
201+
else
202+
{
203+
return GetNativeCtor(type.BaseType, predicate, true);
204+
}
205+
}
187206
}
188207

189208
private bool NeedsExplicitDefaultCtor(INamedTypeSymbol typeSymbol)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#if __ANDROID__
2+
using Android.Content;
3+
4+
namespace Uno.UI.RuntimeTests.Tests.NativeCtorGeneratorTests
5+
{
6+
public partial class MyCustomView : Android.Views.View
7+
{
8+
public MyCustomView(Context context) : base(context) { }
9+
public MyCustomView(Context context, Android.Util.IAttributeSet attributeSet) : base(context, attributeSet) { }
10+
}
11+
12+
public partial class GameBoardCanvas : MyCustomView
13+
{
14+
public GameBoardCanvas(Context context)
15+
: base(context)
16+
{
17+
}
18+
19+
public GameBoardCanvas(Context context, Android.Util.IAttributeSet attributeSet)
20+
: base(context, attributeSet)
21+
{
22+
}
23+
}
24+
}
25+
#endif

0 commit comments

Comments
 (0)