Skip to content

Commit a6a15dc

Browse files
committed
Added attributes generation if missing
1 parent a47824b commit a6a15dc

File tree

3 files changed

+71
-6
lines changed

3 files changed

+71
-6
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 System.IO;
6+
using System.Linq;
7+
using System.Reflection;
8+
using System.Text;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.Text;
11+
12+
namespace Microsoft.Toolkit.Mvvm.SourceGenerators
13+
{
14+
/// <summary>
15+
/// A source generator for necessary nullability attributes.
16+
/// </summary>
17+
[Generator]
18+
public sealed class NullabilityAttributesGenerator : ISourceGenerator
19+
{
20+
/// <inheritdoc/>
21+
public void Initialize(GeneratorInitializationContext context)
22+
{
23+
}
24+
25+
/// <inheritdoc/>
26+
public void Execute(GeneratorExecutionContext context)
27+
{
28+
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullAttribute");
29+
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute");
30+
}
31+
32+
/// <summary>
33+
/// Adds the source for a given attribute type if it's not present already in the compilation.
34+
/// </summary>
35+
private void AddSourceCodeIfTypeIsNotPresent(GeneratorExecutionContext context, string typeFullName)
36+
{
37+
if (context.Compilation.GetTypeByMetadataName(typeFullName) is not null)
38+
{
39+
return;
40+
}
41+
42+
string
43+
typeName = typeFullName.Split('.').Last(),
44+
filename = $"Microsoft.Toolkit.Mvvm.SourceGenerators.EmbeddedResources.{typeName}.cs";
45+
46+
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename);
47+
StreamReader reader = new(stream);
48+
49+
string
50+
originalSource = reader.ReadToEnd(),
51+
outputSource = originalSource.Replace("NETSTANDARD2_0", "true");
52+
53+
context.AddSource($"{typeFullName}.cs", SourceText.From(outputSource, Encoding.UTF8));
54+
}
55+
}
56+
}

Microsoft.Toolkit.Mvvm.SourceGenerators/EmbeddedResources/INotifyPropertyChanged.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.ComponentModel;
10+
using System.Diagnostics.CodeAnalysis;
1011
using System.Runtime.CompilerServices;
1112
using System.Threading.Tasks;
1213

@@ -50,7 +51,7 @@ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
5051
/// <remarks>
5152
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
5253
/// </remarks>
53-
protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string? propertyName = null)
54+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null)
5455
{
5556
if (EqualityComparer<T>.Default.Equals(field, newValue))
5657
{
@@ -75,7 +76,7 @@ protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string
7576
/// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
7677
/// <param name="propertyName">(optional) The name of the property that changed.</param>
7778
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
78-
protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
79+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
7980
{
8081
if (comparer.Equals(field, newValue))
8182
{
@@ -280,7 +281,7 @@ protected bool SetProperty<TModel, T>(T oldValue, T newValue, IEqualityComparer<
280281
/// <paramref name="taskNotifier"/> is different than the previous one, and it does not mean the new
281282
/// <see cref="Task"/> instance passed as argument is in any particular state.
282283
/// </remarks>
283-
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
284+
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
284285
{
285286
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
286287
}
@@ -300,7 +301,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
300301
/// <remarks>
301302
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
302303
/// </remarks>
303-
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
304+
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
304305
{
305306
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
306307
}
@@ -338,7 +339,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
338339
/// <paramref name="taskNotifier"/> is different than the previous one, and it does not mean the new
339340
/// <see cref="Task{TResult}"/> instance passed as argument is in any particular state.
340341
/// </remarks>
341-
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
342+
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
342343
{
343344
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
344345
}
@@ -359,7 +360,7 @@ protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNoti
359360
/// <remarks>
360361
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
361362
/// </remarks>
362-
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
363+
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
363364
{
364365
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
365366
}

Microsoft.Toolkit.Mvvm.SourceGenerators/Microsoft.Toolkit.Mvvm.SourceGenerators.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
<ItemGroup>
1111
<Compile Remove="EmbeddedResources\INotifyPropertyChanged.cs" />
12+
<Compile Remove="EmbeddedResources\NotNullAttribute.cs" />
13+
<Compile Remove="EmbeddedResources\NotNullIfNotNullAttribute.cs" />
1214
<Compile Remove="EmbeddedResources\ObservableObject.cs" />
1315
<Compile Remove="EmbeddedResources\ObservableRecipient.cs" />
1416
</ItemGroup>
@@ -17,6 +19,12 @@
1719
<EmbeddedResource Include="EmbeddedResources\INotifyPropertyChanged.cs">
1820
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1921
</EmbeddedResource>
22+
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\Attributes\NotNullAttribute.cs" Link="EmbeddedResources\NotNullAttribute.cs">
23+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
24+
</EmbeddedResource>
25+
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\Attributes\NotNullIfNotNullAttribute.cs" Link="EmbeddedResources\NotNullIfNotNullAttribute.cs">
26+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
27+
</EmbeddedResource>
2028
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\ComponentModel\ObservableObject.cs" Link="EmbeddedResources\ObservableObject.cs">
2129
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
2230
</EmbeddedResource>

0 commit comments

Comments
 (0)