Skip to content

Commit

Permalink
Add [MemberNotNull] and [MemberNotNullWhen] support
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinchalet committed Oct 6, 2020
1 parent 05b952d commit 3a5c6b7
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 1 deletion.
57 changes: 57 additions & 0 deletions TunnelVisionLabs.ReferenceAssemblyAnnotator/NullableAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,61 @@ internal sealed class DoesNotReturnIfAttribute : Attribute
/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}

/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal class MemberNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with a field or property member.</summary>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullAttribute(string member) => Members = new[] { member };

/// <summary>Initializes the attribute with the list of field and property members.</summary>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullAttribute(params string[] members) => Members = members;

/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}

/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
/// <param name="member">
/// The field or property member that is promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new[] { member };
}

/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
/// <param name="members">
/// The list of field and property members that are promised to be not-null.
/// </param>
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }

/// <summary>Gets field or property member names.</summary>
public string[] Members { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Namespace Global.System.Diagnostics.CodeAnalysis

''' <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
<AttributeUsage(AttributeTargets.Parameter, Inherited:=False)>
Friend NotInheritable Class DoesNotReturnAttribute
Friend NotInheritable Class DoesNotReturnIfAttribute
Inherits Attribute

''' <summary>Initializes the attribute with the specified parameter value.</summary>
Expand All @@ -110,4 +110,65 @@ Namespace Global.System.Diagnostics.CodeAnalysis
Public ReadOnly Property ParameterValue As Boolean
End Class

''' <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
<AttributeUsage(AttributeTargets.Method Or AttributeTargets.Property, Inherited:=False, AllowMultiple:=True)>
Friend NotInheritable Class MemberNotNullAttribute
Inherits Attribute

''' <summary>Initializes the attribute with a field or property member.</summary>
''' <param name="member">
''' The field or property member that is promised to be not-null.
''' </param>
Public Sub New(member As String)
Me.Members = {member}
End Sub

''' <summary>Initializes the attribute with the list of field and property members.</summary>
''' <param name="members">
''' The list of field and property members that are promised to be not-null.
''' </param>
Public Sub New(ParamArray members As String())
Me.Members = members
End Sub

''' <summary>Gets field or property member names.</summary>
Public ReadOnly Property Members As String()
End Class

''' <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
<AttributeUsage(AttributeTargets.Method Or AttributeTargets.Property, Inherited:=False, AllowMultiple:=True)>
Friend NotInheritable Class MemberNotNullWhenAttribute
Inherits Attribute

''' <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
''' <param name="returnValue">
''' The return value condition. If the method returns this value, the associated parameter will not be null.
''' </param>
''' <param name="member">
''' The field or property member that is promised to be not-null.
''' </param>
Public Sub New(returnValue As Boolean, member As String)
Me.ReturnValue = returnValue
Me.Members = {member}
End Sub

''' <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
''' <param name="returnValue">
''' The return value condition. If the method returns this value, the associated parameter will not be null.
''' </param>
''' <param name="members">
''' The list of field and property members that are promised to be not-null.
''' </param>
Public Sub New(ReturnValue As Boolean, ParamArray members As String())
Me.ReturnValue = ReturnValue
Me.Members = members
End Sub

''' <summary>Gets the return value condition.</summary>
Public ReadOnly Property ReturnValue As Boolean

''' <summary>Gets field or property member names.</summary>
Public ReadOnly Property Members As String()
End Class

End Namespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace TunnelVisionLabs.ReferenceAssemblyAnnotator
{
using System;
using Mono.Cecil;
using Mono.Cecil.Rocks;

internal partial class WellKnownTypes
{
private sealed class MemberNotNullAttributeProvidedType : ProvidedAttributeType
{
public MemberNotNullAttributeProvidedType()
: base("System.Diagnostics.CodeAnalysis", "MemberNotNullAttribute")
{
}

protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
{
var constructor1 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
constructor1.Parameters.Add(new ParameterDefinition("member", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
attribute.Methods.Add(constructor1);

var constructor2 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
constructor2.Parameters.Add(new ParameterDefinition("members", ParameterAttributes.None, wellKnownTypes.TypeSystem.String.MakeArrayType()));
attribute.Methods.Add(constructor2);

attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, inherited: false, allowMultiple: true));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace TunnelVisionLabs.ReferenceAssemblyAnnotator
{
using System;
using Mono.Cecil;
using Mono.Cecil.Rocks;

internal partial class WellKnownTypes
{
private sealed class MemberNotNullWhenAttributeProvidedType : ProvidedAttributeType
{
public MemberNotNullWhenAttributeProvidedType()
: base("System.Diagnostics.CodeAnalysis", "MemberNotNullWhenAttribute")
{
}

protected override void ImplementAttribute(ModuleDefinition module, TypeDefinition attribute, WellKnownTypes wellKnownTypes, CustomAttributeFactory attributeFactory)
{
var constructor1 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
constructor1.Parameters.Add(new ParameterDefinition("parameterValue", ParameterAttributes.None, wellKnownTypes.TypeSystem.Boolean));
constructor1.Parameters.Add(new ParameterDefinition("member", ParameterAttributes.None, wellKnownTypes.TypeSystem.String));
attribute.Methods.Add(constructor1);

var constructor2 = MethodFactory.Constructor(wellKnownTypes.TypeSystem);
constructor1.Parameters.Add(new ParameterDefinition("parameterValue", ParameterAttributes.None, wellKnownTypes.TypeSystem.Boolean));
constructor2.Parameters.Add(new ParameterDefinition("members", ParameterAttributes.None, wellKnownTypes.TypeSystem.String.MakeArrayType()));
attribute.Methods.Add(constructor2);

attribute.CustomAttributes.Add(attributeFactory.AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, inherited: false, allowMultiple: true));
}
}
}
}
12 changes: 12 additions & 0 deletions TunnelVisionLabs.ReferenceAssemblyAnnotator/WellKnownTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ internal partial class WellKnownTypes
private readonly WellKnownType _systemDiagnosticsCodeAnalysisDoesNotReturnIfAttribute = new DoesNotReturnIfAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisMaybeNullAttribute = new MaybeNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisMaybeNullWhenAttribute = new MaybeNullWhenAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisMemberNotNullAttribute = new MemberNotNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute = new MemberNotNullWhenAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullAttribute = new NotNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullIfNotNullAttribute = new NotNullIfNotNullAttributeProvidedType();
private readonly WellKnownType _systemDiagnosticsCodeAnalysisNotNullWhenAttribute = new NotNullWhenAttributeProvidedType();
Expand Down Expand Up @@ -70,6 +72,12 @@ public WellKnownTypes(AssemblyDefinition assemblyDefinition)
SystemDiagnosticsCodeAnalysisMaybeNullWhenAttribute = new Lazy<TypeReference>(
() => _systemDiagnosticsCodeAnalysisMaybeNullWhenAttribute.GetOrCreateTypeReference(Module, this),
LazyThreadSafetyMode.ExecutionAndPublication);
SystemDiagnosticsCodeAnalysisMemberNotNullAttribute = new Lazy<TypeReference>(
() => _systemDiagnosticsCodeAnalysisMemberNotNullAttribute.GetOrCreateTypeReference(Module, this),
LazyThreadSafetyMode.ExecutionAndPublication);
SystemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute = new Lazy<TypeReference>(
() => _systemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute.GetOrCreateTypeReference(Module, this),
LazyThreadSafetyMode.ExecutionAndPublication);
SystemDiagnosticsCodeAnalysisNotNullAttribute = new Lazy<TypeReference>(
() => _systemDiagnosticsCodeAnalysisNotNullAttribute.GetOrCreateTypeReference(Module, this),
LazyThreadSafetyMode.ExecutionAndPublication);
Expand Down Expand Up @@ -115,6 +123,10 @@ public WellKnownTypes(AssemblyDefinition assemblyDefinition)

public Lazy<TypeReference> SystemDiagnosticsCodeAnalysisMaybeNullWhenAttribute { get; }

public Lazy<TypeReference> SystemDiagnosticsCodeAnalysisMemberNotNullAttribute { get; }

public Lazy<TypeReference> SystemDiagnosticsCodeAnalysisMemberNotNullWhenAttribute { get; }

public Lazy<TypeReference> SystemDiagnosticsCodeAnalysisNotNullAttribute { get; }

public Lazy<TypeReference> SystemDiagnosticsCodeAnalysisNotNullIfNotNullAttribute { get; }
Expand Down

0 comments on commit 3a5c6b7

Please sign in to comment.