Skip to content

Commit 849a0f1

Browse files
committed
Fix IRecipient generator for partial recipient declarations
1 parent df3b529 commit 849a0f1

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

CommunityToolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3636
.Select(static (item, _) => (item, Interfaces: Execute.GetInterfaces(item)))
3737
.Where(static item => !item.Interfaces.IsEmpty);
3838

39-
// Get the recipient info for all target types
39+
// Get the recipient info for all target types. This pipeline step also needs to filter out
40+
// duplicate recipient definitions (it might happen if a recipient has partial declarations)
4041
IncrementalValuesProvider<RecipientInfo> recipientInfo =
4142
typeAndInterfaceSymbols
4243
.Select(static (item, _) => Execute.GetInfo(item.Type, item.Interfaces))
44+
.WithComparer(RecipientInfo.Comparer.Default)
45+
.Collect()
46+
.Select(static (item, _) => item.Distinct(RecipientInfo.EqualityComparerByFilenameHint))
47+
.SelectMany(static (item, _) => item)
4348
.WithComparer(RecipientInfo.Comparer.Default);
4449

4550
// Check whether the header file is needed

CommunityToolkit.Mvvm.SourceGenerators/Messaging/Models/RecipientInfo.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ internal sealed record RecipientInfo(
2222
string TypeName,
2323
ImmutableArray<string> MessageTypes)
2424
{
25+
/// <summary>
26+
/// Gets an <see cref="IEqualityComparer{T}"/> implementation only matching by <see cref="FilenameHint"/>.
27+
/// </summary>
28+
public static IEqualityComparer<RecipientInfo> EqualityComparerByFilenameHint { get; } = new FilenameHintComparer();
29+
2530
/// <summary>
2631
/// An <see cref="IEqualityComparer{T}"/> implementation for <see cref="RecipientInfo"/>.
2732
/// </summary>
@@ -44,4 +49,22 @@ protected override bool AreEqual(RecipientInfo x, RecipientInfo y)
4449
x.MessageTypes.SequenceEqual(y.MessageTypes);
4550
}
4651
}
52+
53+
/// <summary>
54+
/// An <see cref="IEqualityComparer{T}"/> implementation only matching by <see cref="FilenameHint"/>.
55+
/// </summary>
56+
private sealed class FilenameHintComparer : IEqualityComparer<RecipientInfo>
57+
{
58+
/// <inheritdoc/>
59+
public bool Equals(RecipientInfo x, RecipientInfo y)
60+
{
61+
return x.FilenameHint == y.FilenameHint;
62+
}
63+
64+
/// <inheritdoc/>
65+
public int GetHashCode(RecipientInfo obj)
66+
{
67+
return obj.FilenameHint.GetHashCode();
68+
}
69+
}
4770
}

tests/CommunityToolkit.Mvvm.UnitTests/Test_IRecipientGenerator.cs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ public partial class Test_IRecipientGenerator
1616
[TestMethod]
1717
public void Test_IRecipientGenerator_GeneratedRegistration()
1818
{
19-
StrongReferenceMessenger? messenger = new();
20-
RecipientWithSomeMessages? recipient = new();
19+
StrongReferenceMessenger messenger = new();
20+
RecipientWithSomeMessages recipient = new();
2121

22-
MessageA? messageA = new();
23-
MessageB? messageB = new();
22+
MessageA messageA = new();
23+
MessageB messageB = new();
2424

2525
Action<IMessenger, object, int> registrator = Messaging.__Internals.__IMessengerExtensions.CreateAllMessagesRegistratorWithToken<int>(recipient);
2626

@@ -43,6 +43,15 @@ public void Test_IRecipientGenerator_GeneratedRegistration()
4343
Assert.AreSame(recipient.B, messageB);
4444
}
4545

46+
[TestMethod]
47+
public void Test_IRecipientGenerator_TypeWithMultipleClassDeclarations()
48+
{
49+
RecipientWithMultipleClassDeclarations recipient = new();
50+
51+
// This test really just needs to verify this compiles and executes normally
52+
_ = Messaging.__Internals.__IMessengerExtensions.CreateAllMessagesRegistratorWithToken<int>(recipient);
53+
}
54+
4655
public sealed class RecipientWithSomeMessages :
4756
IRecipient<MessageA>,
4857
IRecipient<MessageB>
@@ -69,4 +78,17 @@ public sealed class MessageA
6978
public sealed class MessageB
7079
{
7180
}
81+
82+
public sealed partial class RecipientWithMultipleClassDeclarations : IRecipient<MessageA>
83+
{
84+
public void Receive(MessageA message)
85+
{
86+
}
87+
}
88+
89+
// This empty partial type declarations needs to be present to ensure the generator
90+
// correctly handles cases where the source type has multiple class declarations.
91+
partial class RecipientWithMultipleClassDeclarations
92+
{
93+
}
7294
}

0 commit comments

Comments
 (0)