Skip to content

Commit

Permalink
Fix property initializers and derived ObservableCollection (#1686)
Browse files Browse the repository at this point in the history
* Fix property initializers not being detected for lookup table generation

* Detect classes that derive from ObservableCollection also for adding SingleItemReadOnlyList workaround

* PR feedback
  • Loading branch information
manodasanW authored Jul 30, 2024
1 parent f8cb6a0 commit d5a6dc9
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 7 deletions.
32 changes: 26 additions & 6 deletions src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,8 @@ private static bool NeedVtableOnLookupTable(SyntaxNode node)
{
return (node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Arguments.Count != 0) ||
node is AssignmentExpressionSyntax ||
node is VariableDeclarationSyntax ||
node is VariableDeclarationSyntax ||
node is PropertyDeclarationSyntax ||
node is ReturnStatementSyntax;
}

Expand Down Expand Up @@ -1090,18 +1091,31 @@ private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupT
else if (context.Node is VariableDeclarationSyntax variableDeclaration)
{
var leftSymbol = context.SemanticModel.GetSymbolInfo(variableDeclaration.Type).Symbol;
foreach (var variable in variableDeclaration.Variables)
if (leftSymbol is INamedTypeSymbol namedType)
{
if (variable.Initializer != null)
foreach (var variable in variableDeclaration.Variables)
{
var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value);
if (leftSymbol is INamedTypeSymbol namedType)
if (variable.Initializer != null)
{
var instantiatedType = context.SemanticModel.GetTypeInfo(variable.Initializer.Value);
AddVtableAttributesForType(instantiatedType, namedType);
}
}
}
}
// Detect scenarios where the property declaration has an initializer and is to a boxed or cast type during initialization.
else if (context.Node is PropertyDeclarationSyntax propertyDeclaration)
{
if (propertyDeclaration.Initializer != null)
{
var leftSymbol = context.SemanticModel.GetSymbolInfo(propertyDeclaration.Type).Symbol;
if (leftSymbol is INamedTypeSymbol namedType)
{
var instantiatedType = context.SemanticModel.GetTypeInfo(propertyDeclaration.Initializer.Value);
AddVtableAttributesForType(instantiatedType, namedType);
}
}
}
// Detect scenarios where the method or property being returned from is doing a box or cast of the type
// in the return statement.
else if (context.Node is ReturnStatementSyntax returnDeclaration && returnDeclaration.Expression is not null)
Expand Down Expand Up @@ -1265,7 +1279,7 @@ internal static void AddVtableAdapterTypeForKnownInterface(ITypeSymbol classType
}
}

if (classType is INamedTypeSymbol namedType && namedType.MetadataName == "ObservableCollection`1")
if (classType is INamedTypeSymbol namedType && IsDerivedFromOrIsObservableCollection(namedType))
{
// ObservableCollection make use of an internal built-in type as part of its
// implementation for INotifyPropertyChanged. Handling that manually here.
Expand Down Expand Up @@ -1299,6 +1313,12 @@ void LookupAndAddVtableAttributeForGenericType(string type, ImmutableArray<IType
}
}
}

bool IsDerivedFromOrIsObservableCollection(INamedTypeSymbol namedType)
{
return namedType.MetadataName == "ObservableCollection`1" ||
(namedType.BaseType is not null && IsDerivedFromOrIsObservableCollection(namedType.BaseType));
}
}

private static void GenerateVtableLookupTable(
Expand Down
29 changes: 28 additions & 1 deletion src/Tests/FunctionalTests/Collections/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using test_component_derived.Nested;
Expand Down Expand Up @@ -99,8 +100,34 @@
networkNames.AddRange(names);
}

instance.BindableIterableProperty = CustomClass.Instances;
if (CustomClass.Instances != instance.BindableIterableProperty)
{
return 101;
}

var customObservableCollection = new CustomObservableCollection();
instance.BindableIterableProperty = customObservableCollection;
if (customObservableCollection != instance.BindableIterableProperty)
{
return 101;
}


return 100;

static bool SequencesEqual<T>(IEnumerable<T> x, params IEnumerable<T>[] list) => list.All((y) => x.SequenceEqual(y));

static bool AllEqual<T>(T[] x, params T[][] list) => list.All((y) => x.SequenceEqual(y));
static bool AllEqual<T>(T[] x, params T[][] list) => list.All((y) => x.SequenceEqual(y));

sealed partial class CustomClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public static IReadOnlyList<CustomClass> Instances { get; } = new CustomClass[] { };
}

sealed partial class CustomObservableCollection : System.Collections.ObjectModel.ObservableCollection<CustomClass>
{
public int CustomCount => Items.Count;
}

0 comments on commit d5a6dc9

Please sign in to comment.