Skip to content

Commit 6e91b62

Browse files
committed
Arrange nullability attributes and adjust code
1 parent 54e3f9e commit 6e91b62

File tree

106 files changed

+596
-325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+596
-325
lines changed

src/NSubstitute/Arg.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using System.Linq.Expressions;
33
using NSubstitute.Core.Arguments;
44

5+
// Disable nullability for client API, so it does not affect clients.
6+
#nullable disable annotations
7+
58
namespace NSubstitute
69
{
710
/// <summary>
@@ -89,7 +92,7 @@ public static ref TDelegate InvokeDelegate<TDelegate>(params object[] arguments)
8992
/// </summary>
9093
public static ref T Do<T>(Action<T> useArgument)
9194
{
92-
return ref ArgumentMatcher.Enqueue<T>(new AnyArgumentMatcher(typeof(T)), x => useArgument((T) x));
95+
return ref ArgumentMatcher.Enqueue<T>(new AnyArgumentMatcher(typeof(T)), x => useArgument((T) x!));
9396
}
9497

9598
/// <summary>

src/NSubstitute/Callback.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
using NSubstitute.Callbacks;
44
using NSubstitute.Core;
55

6+
// Disable nullability for client API, so it does not affect clients.
7+
#nullable disable annotations
8+
69
namespace NSubstitute
710
{
811
/// <summary>
@@ -72,7 +75,8 @@ public static Callback AlwaysThrow<TException>(TException exception) where TExce
7275
return AlwaysThrow(info => exception);
7376
}
7477

75-
protected static Action<CallInfo> ToCallback<TException>(Func<CallInfo, TException> throwThis) where TException : Exception
78+
protected static Action<CallInfo> ToCallback<TException>(Func<CallInfo, TException> throwThis)
79+
where TException : notnull, Exception
7680
{
7781
return ci => { if (throwThis != null) throw throwThis(ci); };
7882
}
@@ -111,8 +115,7 @@ public void Call(CallInfo callInfo)
111115

112116
private void CallFromStack(CallInfo callInfo)
113117
{
114-
Action<CallInfo> callback;
115-
if (callbackQueue.TryDequeue(out callback))
118+
if (callbackQueue.TryDequeue(out var callback))
116119
{
117120
callback(callInfo);
118121
}

src/NSubstitute/Callbacks/ConfiguredCallback.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using NSubstitute.Core;
33

4+
// Disable nullability for client API, so it does not affect clients.
5+
#nullable disable annotations
6+
47
namespace NSubstitute.Callbacks
58
{
69
public class ConfiguredCallback : EndCallbackChain

src/NSubstitute/Compatibility/CompatArg.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
22
using System.Linq.Expressions;
33

4+
// Disable nullability for client API, so it does not affect clients.
5+
#nullable disable annotations
6+
47
namespace NSubstitute.Compatibility
58
{
69
/// <summary>
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_NULLABILITY
2+
3+
// This was copied from https://github.com/dotnet/runtime/blob/39b9607807f29e48cae4652cd74735182b31182e/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
4+
// and updated to have the scope of the attributes be internal.
5+
namespace System.Diagnostics.CodeAnalysis
6+
{
7+
8+
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
9+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
10+
internal sealed class AllowNullAttribute : Attribute { }
11+
12+
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
13+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
14+
internal sealed class DisallowNullAttribute : Attribute { }
15+
16+
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
17+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
18+
internal sealed class MaybeNullAttribute : Attribute { }
19+
20+
/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
21+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
22+
internal sealed class NotNullAttribute : Attribute { }
23+
24+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
25+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
26+
internal sealed class MaybeNullWhenAttribute : Attribute
27+
{
28+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
29+
/// <param name="returnValue">
30+
/// The return value condition. If the method returns this value, the associated parameter may be null.
31+
/// </param>
32+
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
33+
34+
/// <summary>Gets the return value condition.</summary>
35+
public bool ReturnValue { get; }
36+
}
37+
38+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
39+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
40+
internal sealed class NotNullWhenAttribute : Attribute
41+
{
42+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
43+
/// <param name="returnValue">
44+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
45+
/// </param>
46+
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
47+
48+
/// <summary>Gets the return value condition.</summary>
49+
public bool ReturnValue { get; }
50+
}
51+
52+
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
53+
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
54+
internal sealed class NotNullIfNotNullAttribute : Attribute
55+
{
56+
/// <summary>Initializes the attribute with the associated parameter name.</summary>
57+
/// <param name="parameterName">
58+
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
59+
/// </param>
60+
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
61+
62+
/// <summary>Gets the associated parameter name.</summary>
63+
public string ParameterName { get; }
64+
}
65+
66+
/// <summary>Applied to a method that will never return under any circumstance.</summary>
67+
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
68+
internal sealed class DoesNotReturnAttribute : Attribute { }
69+
70+
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
71+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
72+
internal sealed class DoesNotReturnIfAttribute : Attribute
73+
{
74+
/// <summary>Initializes the attribute with the specified parameter value.</summary>
75+
/// <param name="parameterValue">
76+
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
77+
/// the associated parameter matches this value.
78+
/// </param>
79+
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
80+
81+
/// <summary>Gets the condition parameter value.</summary>
82+
public bool ParameterValue { get; }
83+
}
84+
85+
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
86+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
87+
internal sealed class MemberNotNullAttribute : Attribute
88+
{
89+
/// <summary>Initializes the attribute with a field or property member.</summary>
90+
/// <param name="member">
91+
/// The field or property member that is promised to be not-null.
92+
/// </param>
93+
public MemberNotNullAttribute(string member) => Members = new[] { member };
94+
95+
/// <summary>Initializes the attribute with the list of field and property members.</summary>
96+
/// <param name="members">
97+
/// The list of field and property members that are promised to be not-null.
98+
/// </param>
99+
public MemberNotNullAttribute(params string[] members) => Members = members;
100+
101+
/// <summary>Gets field or property member names.</summary>
102+
public string[] Members { get; }
103+
}
104+
105+
/// <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>
106+
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
107+
internal sealed class MemberNotNullWhenAttribute : Attribute
108+
{
109+
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
110+
/// <param name="returnValue">
111+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
112+
/// </param>
113+
/// <param name="member">
114+
/// The field or property member that is promised to be not-null.
115+
/// </param>
116+
public MemberNotNullWhenAttribute(bool returnValue, string member)
117+
{
118+
ReturnValue = returnValue;
119+
Members = new[] { member };
120+
}
121+
122+
/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
123+
/// <param name="returnValue">
124+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
125+
/// </param>
126+
/// <param name="members">
127+
/// The list of field and property members that are promised to be not-null.
128+
/// </param>
129+
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
130+
{
131+
ReturnValue = returnValue;
132+
Members = members;
133+
}
134+
135+
/// <summary>Gets the return value condition.</summary>
136+
public bool ReturnValue { get; }
137+
138+
/// <summary>Gets field or property member names.</summary>
139+
public string[] Members { get; }
140+
}
141+
}
142+
#endif

src/NSubstitute/Core/Argument.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ namespace NSubstitute.Core
55
{
66
public class Argument
77
{
8-
private readonly ICall _call;
8+
private readonly ICall? _call;
99
private readonly int _argIndex;
1010

11-
private readonly Type _declaredType;
12-
private readonly Func<object> _getValue;
13-
private readonly Action<object> _setValue;
11+
private readonly Type? _declaredType;
12+
private readonly Func<object?>? _getValue;
13+
private readonly Action<object?>? _setValue;
1414

1515
[Obsolete("This constructor overload is deprecated and will be removed in the next version.")]
16-
public Argument(Type declaredType, Func<object> getValue, Action<object> setValue)
16+
public Argument(Type declaredType, Func<object?> getValue, Action<object?> setValue)
1717
{
1818
_declaredType = declaredType;
1919
_getValue = getValue;
@@ -26,9 +26,9 @@ public Argument(ICall call, int argIndex)
2626
_argIndex = argIndex;
2727
}
2828

29-
public object Value
29+
public object? Value
3030
{
31-
get => _getValue != null ? _getValue() : _call.GetArguments()[_argIndex];
31+
get => _getValue != null ? _getValue() : _call!.GetArguments()[_argIndex];
3232
set
3333
{
3434
if (_setValue != null)
@@ -37,14 +37,14 @@ public object Value
3737
}
3838
else
3939
{
40-
_call.GetArguments()[_argIndex] = value;
40+
_call!.GetArguments()[_argIndex] = value;
4141
}
4242
}
4343
}
4444

4545
public bool IsByRef => DeclaredType.IsByRef;
4646

47-
public Type DeclaredType => _declaredType ?? _call.GetParameterInfos()[_argIndex].ParameterType;
47+
public Type DeclaredType => _declaredType ?? _call!.GetParameterInfos()[_argIndex].ParameterType;
4848

4949
public Type ActualType => Value == null ? DeclaredType : Value.GetType();
5050

@@ -65,7 +65,7 @@ public bool CanSetValueWithInstanceOf(Type type)
6565

6666
private static Type AsNonByRefType(Type type)
6767
{
68-
return type.IsByRef ? type.GetElementType() : type;
68+
return type.IsByRef ? type.GetElementType()! : type;
6969
}
7070
}
7171
}

src/NSubstitute/Core/Arguments/AnyArgumentMatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public AnyArgumentMatcher(Type typeArgMustBeCompatibleWith)
1313

1414
public override string ToString() => "any " + _typeArgMustBeCompatibleWith.GetNonMangledTypeName();
1515

16-
public bool IsSatisfiedBy(object argument) => argument.IsCompatibleWith(_typeArgMustBeCompatibleWith);
16+
public bool IsSatisfiedBy(object? argument) => argument.IsCompatibleWith(_typeArgMustBeCompatibleWith);
1717
}
1818
}

src/NSubstitute/Core/Arguments/ArgumentFormatter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ public class ArgumentFormatter : IArgumentFormatter
88
{
99
internal static IArgumentFormatter Default { get; } = new ArgumentFormatter();
1010

11-
public string Format(object argument, bool highlight)
11+
public string Format(object? argument, bool highlight)
1212
{
1313
var formatted = Format(argument);
1414
return highlight ? "*" + formatted + "*" : formatted;
1515
}
1616

17-
private string Format(object arg)
17+
private string Format(object? arg)
1818
{
1919
switch (arg)
2020
{
@@ -24,11 +24,11 @@ private string Format(object arg)
2424
case string str:
2525
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", str);
2626

27-
case object obj when obj.GetType().GetMethod(nameof(ToString), Type.EmptyTypes).DeclaringType == typeof(object):
27+
case object obj when obj.GetType().GetMethod(nameof(ToString), Type.EmptyTypes)!.DeclaringType == typeof(object):
2828
return arg.GetType().GetNonMangledTypeName();
2929

3030
default:
31-
return arg.ToString();
31+
return arg.ToString() ?? string.Empty;
3232
}
3333
}
3434
}

src/NSubstitute/Core/Arguments/ArgumentMatchInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
{
33
public class ArgumentMatchInfo
44
{
5-
public ArgumentMatchInfo(int index, object argument, IArgumentSpecification specification)
5+
public ArgumentMatchInfo(int index, object? argument, IArgumentSpecification specification)
66
{
77
Index = index;
88
_argument = argument;
99
_specification = specification;
1010
}
1111

12-
private readonly object _argument;
12+
private readonly object? _argument;
1313
private readonly IArgumentSpecification _specification;
1414
public int Index { get; private set; }
1515

@@ -23,14 +23,14 @@ public string DescribeNonMatch()
2323
return string.Format("{0}{1}", argIndexPrefix, describeNonMatch.Replace("\n", "\n".PadRight(argIndexPrefix.Length + 1)));
2424
}
2525

26-
public bool Equals(ArgumentMatchInfo other)
26+
public bool Equals(ArgumentMatchInfo? other)
2727
{
2828
if (ReferenceEquals(null, other)) return false;
2929
if (ReferenceEquals(this, other)) return true;
3030
return other.Index == Index && Equals(other._argument, _argument) && Equals(other._specification, _specification);
3131
}
3232

33-
public override bool Equals(object obj)
33+
public override bool Equals(object? obj)
3434
{
3535
if (ReferenceEquals(null, obj)) return false;
3636
if (ReferenceEquals(this, obj)) return true;
@@ -44,7 +44,7 @@ public override int GetHashCode()
4444
{
4545
int result = Index;
4646
result = (result*397) ^ (_argument != null ? _argument.GetHashCode() : 0);
47-
result = (result*397) ^ (_specification != null ? _specification.GetHashCode() : 0);
47+
result = (result*397) ^ _specification.GetHashCode();
4848
return result;
4949
}
5050
}

src/NSubstitute/Core/Arguments/ArgumentMatcher.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23

34
namespace NSubstitute.Core.Arguments
45
{
@@ -30,7 +31,7 @@ internal static ref T Enqueue<T>(IArgumentMatcher argumentMatcher)
3031
return ref EnqueueArgSpecification<T>(new ArgumentSpecification(typeof(T), argumentMatcher));
3132
}
3233

33-
internal static ref T Enqueue<T>(IArgumentMatcher argumentMatcher, Action<object> action)
34+
internal static ref T Enqueue<T>(IArgumentMatcher argumentMatcher, Action<object?> action)
3435
{
3536
return ref EnqueueArgSpecification<T>(new ArgumentSpecification(typeof(T), argumentMatcher, action));
3637
}
@@ -50,7 +51,7 @@ public GenericToNonGenericMatcherProxy(IArgumentMatcher<T> matcher)
5051
_matcher = matcher;
5152
}
5253

53-
public bool IsSatisfiedBy(object argument) => _matcher.IsSatisfiedBy((T) argument);
54+
public bool IsSatisfiedBy(object? argument) => _matcher.IsSatisfiedBy((T) argument!);
5455
}
5556

5657
private class GenericToNonGenericMatcherProxyWithDescribe<T> : GenericToNonGenericMatcherProxy<T>, IDescribeNonMatches
@@ -60,11 +61,12 @@ public GenericToNonGenericMatcherProxyWithDescribe(IArgumentMatcher<T> matcher)
6061
if (matcher as IDescribeNonMatches == null) throw new ArgumentException("Should implement IDescribeNonMatches type.");
6162
}
6263

63-
public string DescribeFor(object argument) => ((IDescribeNonMatches) _matcher).DescribeFor(argument);
64+
public string DescribeFor(object? argument) => ((IDescribeNonMatches) _matcher).DescribeFor(argument);
6465
}
6566

6667
private class DefaultValueContainer<T>
6768
{
69+
[AllowNull]
6870
public T Value;
6971
}
7072
}

0 commit comments

Comments
 (0)