Skip to content

Commit

Permalink
Added attributes generation if missing
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Jul 30, 2021
1 parent a5e1045 commit dad3018
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.Toolkit.Mvvm.SourceGenerators
{
/// <summary>
/// A source generator for necessary nullability attributes.
/// </summary>
[Generator]
public sealed class NullabilityAttributesGenerator : ISourceGenerator
{
/// <inheritdoc/>
public void Initialize(GeneratorInitializationContext context)
{
}

/// <inheritdoc/>
public void Execute(GeneratorExecutionContext context)
{
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullAttribute");
AddSourceCodeIfTypeIsNotPresent(context, "System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute");
}

/// <summary>
/// Adds the source for a given attribute type if it's not present already in the compilation.
/// </summary>
private void AddSourceCodeIfTypeIsNotPresent(GeneratorExecutionContext context, string typeFullName)
{
if (context.Compilation.GetTypeByMetadataName(typeFullName) is not null)
{
return;
}

string
typeName = typeFullName.Split('.').Last(),
filename = $"Microsoft.Toolkit.Mvvm.SourceGenerators.EmbeddedResources.{typeName}.cs";

Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename);
StreamReader reader = new(stream);

string
originalSource = reader.ReadToEnd(),
outputSource = originalSource.Replace("NETSTANDARD2_0", "true");

context.AddSource($"{typeFullName}.cs", SourceText.From(outputSource, Encoding.UTF8));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

Expand Down Expand Up @@ -50,7 +51,7 @@ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
/// <remarks>
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
/// </remarks>
protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string? propertyName = null)
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
Expand All @@ -75,7 +76,7 @@ protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string
/// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
/// <param name="propertyName">(optional) The name of the property that changed.</param>
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
{
if (comparer.Equals(field, newValue))
{
Expand Down Expand Up @@ -280,7 +281,7 @@ protected bool SetProperty<TModel, T>(T oldValue, T newValue, IEqualityComparer<
/// <paramref name="taskNotifier"/> is different than the previous one, and it does not mean the new
/// <see cref="Task"/> instance passed as argument is in any particular state.
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
}
Expand All @@ -300,7 +301,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
/// <remarks>
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
}
Expand Down Expand Up @@ -338,7 +339,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
/// <paramref name="taskNotifier"/> is different than the previous one, and it does not mean the new
/// <see cref="Task{TResult}"/> instance passed as argument is in any particular state.
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
}
Expand All @@ -359,7 +360,7 @@ protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNoti
/// <remarks>
/// The <see cref="PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
/// </remarks>
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
{
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

<ItemGroup>
<Compile Remove="EmbeddedResources\INotifyPropertyChanged.cs" />
<Compile Remove="EmbeddedResources\NotNullAttribute.cs" />
<Compile Remove="EmbeddedResources\NotNullIfNotNullAttribute.cs" />
<Compile Remove="EmbeddedResources\ObservableObject.cs" />
<Compile Remove="EmbeddedResources\ObservableRecipient.cs" />
</ItemGroup>
Expand All @@ -17,6 +19,12 @@
<EmbeddedResource Include="EmbeddedResources\INotifyPropertyChanged.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\Attributes\NotNullAttribute.cs" Link="EmbeddedResources\NotNullAttribute.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\Attributes\NotNullIfNotNullAttribute.cs" Link="EmbeddedResources\NotNullIfNotNullAttribute.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="..\Microsoft.Toolkit.Mvvm\ComponentModel\ObservableObject.cs" Link="EmbeddedResources\ObservableObject.cs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
Expand Down

0 comments on commit dad3018

Please sign in to comment.