Skip to content

Commit d9c315c

Browse files
authored
Merge pull request #110 from CommunityToolkit/dev/fix-observable-recipient-attribute-inheritance
Fix [ObservableRecipient] with inherited base attributes
2 parents 3d7b45c + c1cb029 commit d9c315c

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, Observab
8282
// In order to use [ObservableRecipient], the target type needs to inherit from ObservableObject,
8383
// or be annotated with [ObservableObject] or [INotifyPropertyChanged] (with additional helpers).
8484
if (!typeSymbol.InheritsFrom("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObject") &&
85-
!typeSymbol.GetAttributes().Any(static a => a.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute") == true) &&
86-
!typeSymbol.GetAttributes().Any(static a =>
85+
!typeSymbol.HasOrInheritsAttribute(static a => a.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute") == true) &&
86+
!typeSymbol.HasOrInheritsAttribute(static a =>
8787
a.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute") == true &&
8888
!a.HasNamedArgument("IncludeAdditionalHelperMethods", false)))
8989
{

CommunityToolkit.Mvvm.SourceGenerators/Extensions/INamedTypeSymbolExtensions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
6+
using System.Linq;
57
using System.Text;
68
using Microsoft.CodeAnalysis;
79

@@ -62,4 +64,23 @@ public static bool InheritsFrom(this INamedTypeSymbol typeSymbol, string name)
6264

6365
return false;
6466
}
67+
68+
/// <summary>
69+
/// Checks whether or not a given <see cref="INamedTypeSymbol"/> has or inherits a specified attribute.
70+
/// </summary>
71+
/// <param name="typeSymbol">The target <see cref="INamedTypeSymbol"/> instance to check.</param>
72+
/// <param name="predicate">The predicate used to match available attributes.</param>
73+
/// <returns>Whether or not <paramref name="typeSymbol"/> has an attribute matching <paramref name="predicate"/>.</returns>
74+
public static bool HasOrInheritsAttribute(this INamedTypeSymbol typeSymbol, Func<AttributeData, bool> predicate)
75+
{
76+
for (INamedTypeSymbol? currentType = typeSymbol; currentType is not null; currentType = currentType.BaseType)
77+
{
78+
if (currentType.GetAttributes().Any(predicate))
79+
{
80+
return true;
81+
}
82+
}
83+
84+
return false;
85+
}
6586
}

tests/CommunityToolkit.Mvvm.UnitTests/Test_ObservableRecipientAttribute.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,25 @@ private partial void OnDeactivated()
260260
OnDeactivatedResult = true;
261261
}
262262
}
263+
264+
// See https://github.com/CommunityToolkit/dotnet/issues/109
265+
[TestMethod]
266+
public void Test_ObservableRecipientAttribute_WorksWithBaseClassWithObservableObjectAttribute()
267+
{
268+
ViewModelWithOnlyObservableRecipientAttribute model = new();
269+
270+
// This test method really only needs the two classes below to compile at all
271+
Assert.IsTrue(model is INotifyPropertyChanged); // From [ObservableObject]
272+
Assert.IsFalse(model.IsActive); // From [ObservableRecipient]
273+
}
274+
275+
[ObservableObject]
276+
public partial class BaseViewModelWithObservableObjectAttribute
277+
{
278+
}
279+
280+
[ObservableRecipient]
281+
public partial class ViewModelWithOnlyObservableRecipientAttribute : BaseViewModelWithObservableObjectAttribute
282+
{
283+
}
263284
}

0 commit comments

Comments
 (0)