Skip to content

Commit ab5b03d

Browse files
Merge pull request #4168 from Sergio0694/bugfix/INPC-generator-attributes
Fixed nullability attributes generation on .NET Standard targets
2 parents f995c16 + 5c1b35b commit ab5b03d

File tree

7 files changed

+118
-2
lines changed

7 files changed

+118
-2
lines changed

Microsoft.Toolkit.Mvvm.SourceGenerators/Attributes/NullabilityAttributesGenerator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ public void Execute(GeneratorExecutionContext context)
3434
/// </summary>
3535
private void AddSourceCodeIfTypeIsNotPresent(GeneratorExecutionContext context, string typeFullName)
3636
{
37-
if (context.Compilation.GetTypeByMetadataName(typeFullName) is not null)
37+
// Check that the target attributes are not available in the consuming project. To ensure that
38+
// this works fine both in .NET (Core) and .NET Standard implementations, we also need to check
39+
// that the target types are declared as public (we assume that in this case those types are from the BCL).
40+
// This avoids issues on .NET Standard with Roslyn also seeing internal types from referenced assemblies.
41+
if (context.Compilation.GetTypeByMetadataName(typeFullName) is { DeclaredAccessibility: Accessibility.Public })
3842
{
3943
return;
4044
}

UnitTests/UnitTests.NetCore/Mvvm/Test_INotifyPropertyChangedAttribute.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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.Collections.Generic;
56
using System.ComponentModel;
67
using System.Diagnostics.CodeAnalysis;
78
using System.Reflection;
@@ -75,5 +76,56 @@ public void Test_INotifyPropertyChanged_WithoutHelpers()
7576
public partial class SampleModelWithoutHelpers
7677
{
7778
}
79+
80+
[TestCategory("Mvvm")]
81+
[TestMethod]
82+
public void Test_INotifyPropertyChanged_WithGeneratedProperties()
83+
{
84+
Assert.IsTrue(typeof(INotifyPropertyChanged).IsAssignableFrom(typeof(SampleModelWithINPCAndObservableProperties)));
85+
Assert.IsFalse(typeof(INotifyPropertyChanging).IsAssignableFrom(typeof(SampleModelWithINPCAndObservableProperties)));
86+
87+
SampleModelWithINPCAndObservableProperties model = new();
88+
List<PropertyChangedEventArgs> eventArgs = new();
89+
90+
model.PropertyChanged += (s, e) => eventArgs.Add(e);
91+
92+
model.X = 42;
93+
model.Y = 66;
94+
95+
Assert.AreEqual(eventArgs.Count, 2);
96+
Assert.AreEqual(eventArgs[0].PropertyName, nameof(SampleModelWithINPCAndObservableProperties.X));
97+
Assert.AreEqual(eventArgs[1].PropertyName, nameof(SampleModelWithINPCAndObservableProperties.Y));
98+
}
99+
100+
// See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4167
101+
[INotifyPropertyChanged]
102+
public partial class SampleModelWithINPCAndObservableProperties
103+
{
104+
[ObservableProperty]
105+
private int x;
106+
107+
[ObservableProperty]
108+
private int y;
109+
}
110+
111+
[TestCategory("Mvvm")]
112+
[TestMethod]
113+
public void Test_INotifyPropertyChanged_WithGeneratedProperties_ExternalNetStandard20Assembly()
114+
{
115+
Assert.IsTrue(typeof(INotifyPropertyChanged).IsAssignableFrom(typeof(NetStandard.SampleModelWithINPCAndObservableProperties)));
116+
Assert.IsFalse(typeof(INotifyPropertyChanging).IsAssignableFrom(typeof(NetStandard.SampleModelWithINPCAndObservableProperties)));
117+
118+
NetStandard.SampleModelWithINPCAndObservableProperties model = new();
119+
List<PropertyChangedEventArgs> eventArgs = new();
120+
121+
model.PropertyChanged += (s, e) => eventArgs.Add(e);
122+
123+
model.X = 42;
124+
model.Y = 66;
125+
126+
Assert.AreEqual(eventArgs.Count, 2);
127+
Assert.AreEqual(eventArgs[0].PropertyName, nameof(NetStandard.SampleModelWithINPCAndObservableProperties.X));
128+
Assert.AreEqual(eventArgs[1].PropertyName, nameof(NetStandard.SampleModelWithINPCAndObservableProperties.Y));
129+
}
78130
}
79131
}

UnitTests/UnitTests.NetCore/UnitTests.NetCore.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<ProjectReference Include="..\..\Microsoft.Toolkit.Mvvm\Microsoft.Toolkit.Mvvm.csproj" />
1111
<ProjectReference Include="..\..\Microsoft.Toolkit.Diagnostics\Microsoft.Toolkit.Diagnostics.csproj" />
1212
<ProjectReference Include="..\..\Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="contentfiles;build" />
13+
<ProjectReference Include="..\UnitTests.NetStandard\UnitTests.NetStandard.csproj" />
1314
</ItemGroup>
1415

1516
<ItemGroup>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Toolkit.Mvvm.ComponentModel;
6+
7+
namespace UnitTests.NetStandard
8+
{
9+
/// <summary>
10+
/// See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4167.
11+
/// This model in particular is loaded from an external .NET Standard 2.0 assembly.
12+
/// </summary>
13+
[INotifyPropertyChanged]
14+
public partial class SampleModelWithINPCAndObservableProperties
15+
{
16+
[ObservableProperty]
17+
private int x;
18+
19+
[ObservableProperty]
20+
private int y;
21+
}
22+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>9.0</LangVersion>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<ProjectReference Include="..\..\Microsoft.Toolkit.Mvvm\Microsoft.Toolkit.Mvvm.csproj" />
10+
<ProjectReference Include="..\..\Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="contentfiles;build" />
11+
</ItemGroup>
12+
13+
</Project>

Windows Community Toolkit (NET).slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"UnitTests\\UnitTests.HighPerformance.NetCore\\UnitTests.HighPerformance.NetCore.csproj",
1111
"UnitTests\\UnitTests.HighPerformance.Shared\\UnitTests.HighPerformance.Shared.shproj",
1212
"UnitTests\\UnitTests.NetCore\\UnitTests.NetCore.csproj",
13+
"UnitTests\\UnitTests.NetStandard\\UnitTests.NetStandard.csproj",
1314
"UnitTests\\UnitTests.Shared\\UnitTests.Shared.shproj",
1415
"UnitTests\\UnitTests.SourceGenerators\\UnitTests.SourceGenerators.csproj",
1516
]

Windows Community Toolkit.sln

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Co
159159
EndProject
160160
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Mvvm.SourceGenerators", "Microsoft.Toolkit.Mvvm.SourceGenerators\Microsoft.Toolkit.Mvvm.SourceGenerators.csproj", "{E24D1146-5AD8-498F-A518-4890D8BF4937}"
161161
EndProject
162-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.SourceGenerators", "UnitTests\UnitTests.SourceGenerators\UnitTests.SourceGenerators.csproj", "{338C3BE4-2E71-4F21-AD30-03FDBB47A272}"
162+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests.SourceGenerators", "UnitTests\UnitTests.SourceGenerators\UnitTests.SourceGenerators.csproj", "{338C3BE4-2E71-4F21-AD30-03FDBB47A272}"
163+
EndProject
164+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.NetStandard", "UnitTests\UnitTests.NetStandard\UnitTests.NetStandard.csproj", "{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}"
163165
EndProject
164166
Global
165167
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -1154,6 +1156,26 @@ Global
11541156
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x64.Build.0 = Release|Any CPU
11551157
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x86.ActiveCfg = Release|Any CPU
11561158
{338C3BE4-2E71-4F21-AD30-03FDBB47A272}.Release|x86.Build.0 = Release|Any CPU
1159+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1160+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
1161+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|ARM.ActiveCfg = Debug|Any CPU
1162+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|ARM.Build.0 = Debug|Any CPU
1163+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
1164+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|ARM64.Build.0 = Debug|Any CPU
1165+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|x64.ActiveCfg = Debug|Any CPU
1166+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|x64.Build.0 = Debug|Any CPU
1167+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|x86.ActiveCfg = Debug|Any CPU
1168+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Debug|x86.Build.0 = Debug|Any CPU
1169+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
1170+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|Any CPU.Build.0 = Release|Any CPU
1171+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|ARM.ActiveCfg = Release|Any CPU
1172+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|ARM.Build.0 = Release|Any CPU
1173+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|ARM64.ActiveCfg = Release|Any CPU
1174+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|ARM64.Build.0 = Release|Any CPU
1175+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|x64.ActiveCfg = Release|Any CPU
1176+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|x64.Build.0 = Release|Any CPU
1177+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|x86.ActiveCfg = Release|Any CPU
1178+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1}.Release|x86.Build.0 = Release|Any CPU
11571179
EndGlobalSection
11581180
GlobalSection(SolutionProperties) = preSolution
11591181
HideSolutionNode = FALSE
@@ -1204,6 +1226,7 @@ Global
12041226
{3307BC1D-5D71-41C6-A1B3-B113B8242D08} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
12051227
{099B60FD-DAD6-4648-9DE2-8DBF9DCD9557} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC}
12061228
{338C3BE4-2E71-4F21-AD30-03FDBB47A272} = {B30036C4-D514-4E5B-A323-587A061772CE}
1229+
{D9C82C0D-31D7-4888-B024-3CF3A4F54FE1} = {B30036C4-D514-4E5B-A323-587A061772CE}
12071230
EndGlobalSection
12081231
GlobalSection(ExtensibilityGlobals) = postSolution
12091232
SolutionGuid = {5403B0C4-F244-4F73-A35C-FE664D0F4345}

0 commit comments

Comments
 (0)