diff --git a/src/Moq/ActionObserver.cs b/src/Moq/ActionObserver.cs index 128dce6d1..6b8e9bb19 100644 --- a/src/Moq/ActionObserver.cs +++ b/src/Moq/ActionObserver.cs @@ -27,14 +27,14 @@ namespace Moq /// sealed class ActionObserver : ExpressionReconstructor { - public override Expression> ReconstructExpression(Action action, object[] ctorArgs = null) + public override Expression> ReconstructExpression(Action action, object?[]? ctorArgs = null) { using (var matcherObserver = MatcherObserver.Activate()) { // Create the root recording proxy: var root = (T)CreateProxy(typeof(T), ctorArgs, matcherObserver, out var rootRecorder); - Exception error = null; + Exception? error = null; try { // Execute the delegate. The root recorder will automatically "mock" return values @@ -61,7 +61,7 @@ public override Expression> ReconstructExpression(Action action, var invocation = recorder.Invocation; if (invocation != null) { - var resultType = invocation.Method.DeclaringType; + var resultType = invocation.Method.DeclaringType!; if (resultType.IsAssignableFrom(body.Type) == false) { if (AwaitableFactory.TryGet(body.Type) is { } awaitableHandler @@ -128,7 +128,7 @@ Expression[] GetArgumentExpressions(Invocation invocation, Match[] matches) // it will have left behind a `default(T)` argument, possibly coerced to the parameter type. // Therefore, we attempt to reproduce such coercions using `Convert.ChangeType`: Type defaultValueType = matches[matchIndex].RenderExpression.Type; - object defaultValue = defaultValueType.GetDefaultValue(); + object? defaultValue = defaultValueType.GetDefaultValue(); try { defaultValue = Convert.ChangeType(defaultValue, parameterTypes[argumentIndex]); @@ -178,7 +178,7 @@ Expression[] GetArgumentExpressions(Invocation invocation, Match[] matches) CultureInfo.CurrentCulture, Resources.MatcherAssignmentFailedDuringExpressionReconstruction, matches.Length, - $"{invocation.Method.DeclaringType.GetFormattedName()}.{invocation.Method.Name}")); + $"{invocation.Method.DeclaringType!.GetFormattedName()}.{invocation.Method.Name}")); } bool CanDistribute(int msi, int asi) @@ -228,10 +228,10 @@ bool CanDistribute(int msi, int asi) } // Creates a proxy (way more light-weight than a `Mock`!) with an invocation `Recorder` attached to it. - static IProxy CreateProxy(Type type, object[] ctorArgs, MatcherObserver matcherObserver, out Recorder recorder) + static IProxy CreateProxy(Type type, object?[]? ctorArgs, MatcherObserver matcherObserver, out Recorder recorder) { recorder = new Recorder(matcherObserver); - return (IProxy)ProxyFactory.Instance.CreateProxy(type, recorder, Type.EmptyTypes, ctorArgs ?? new object[0]); + return (IProxy)ProxyFactory.Instance.CreateProxy(type, recorder, Type.EmptyTypes, ctorArgs ?? new object?[0]); } @@ -241,9 +241,9 @@ sealed class Recorder : IInterceptor { readonly MatcherObserver matcherObserver; int creationTimestamp; - Invocation invocation; + Invocation? invocation; int invocationTimestamp; - object returnValue; + object? returnValue; public Recorder(MatcherObserver matcherObserver) { @@ -253,7 +253,7 @@ public Recorder(MatcherObserver matcherObserver) this.creationTimestamp = this.matcherObserver.GetNextTimestamp(); } - public Invocation Invocation => this.invocation; + public Invocation? Invocation => this.invocation; public IEnumerable Matches { @@ -264,7 +264,7 @@ public IEnumerable Matches } } - public Recorder Next => (Awaitable.TryGetResultRecursive(this.returnValue) as IProxy)?.Interceptor as Recorder; + public Recorder? Next => (Awaitable.TryGetResultRecursive(this.returnValue) as IProxy)?.Interceptor as Recorder; public void Intercept(Invocation invocation) { diff --git a/src/Moq/AsInterface.cs b/src/Moq/AsInterface.cs index db6b6636e..7ba906e03 100644 --- a/src/Moq/AsInterface.cs +++ b/src/Moq/AsInterface.cs @@ -19,9 +19,9 @@ public AsInterface(Mock owner) internal override List AdditionalInterfaces => this.owner.AdditionalInterfaces; - internal override Dictionary ConfiguredDefaultValues => this.owner.ConfiguredDefaultValues; + internal override Dictionary ConfiguredDefaultValues => this.owner.ConfiguredDefaultValues; - internal override object[] ConstructorArguments => this.owner.ConstructorArguments; + internal override object?[] ConstructorArguments => this.owner.ConstructorArguments; internal override InvocationCollection MutableInvocations => this.owner.MutableInvocations; @@ -49,7 +49,7 @@ public override DefaultValueProvider DefaultValueProvider public override TInterface Object { - get { return this.owner.Object as TInterface; } + get { return (TInterface)this.owner.Object; } } internal override SetupCollection MutableSetups => this.owner.MutableSetups; @@ -72,7 +72,7 @@ protected override object OnGetObject() public override string ToString() { - return this.owner.ToString(); + return this.owner.ToString()!; } } } diff --git a/src/Moq/Async/Awaitable.cs b/src/Moq/Async/Awaitable.cs index 192d64aea..9afe9df9b 100644 --- a/src/Moq/Async/Awaitable.cs +++ b/src/Moq/Async/Awaitable.cs @@ -14,7 +14,7 @@ static class Awaitable /// this method will return 42. /// /// The (possibly awaitable) object to be "unwrapped". - public static object TryGetResultRecursive(object obj) + public static object? TryGetResultRecursive(object? obj) { if (obj != null && AwaitableFactory.TryGet(obj.GetType()) is { } awaitableFactory diff --git a/src/Moq/Async/AwaitableFactory.cs b/src/Moq/Async/AwaitableFactory.cs index 8c51868bf..8de61a3e7 100644 --- a/src/Moq/Async/AwaitableFactory.cs +++ b/src/Moq/Async/AwaitableFactory.cs @@ -27,7 +27,7 @@ static IAwaitableFactory Create(Type awaitableFactoryType, Type awaitableType) { return (IAwaitableFactory)Activator.CreateInstance( awaitableFactoryType.MakeGenericType( - awaitableType.GetGenericArguments())); + awaitableType.GetGenericArguments()))!; } public static IAwaitableFactory? TryGet(Type type) diff --git a/src/Moq/Async/AwaitableFactory`1.cs b/src/Moq/Async/AwaitableFactory`1.cs index 3b88a9194..09dfda2aa 100644 --- a/src/Moq/Async/AwaitableFactory`1.cs +++ b/src/Moq/Async/AwaitableFactory`1.cs @@ -14,12 +14,13 @@ namespace Moq.Async /// for awaitables that do not produce a result when awaited. /// abstract class AwaitableFactory : IAwaitableFactory + where TAwaitable : notnull { Type IAwaitableFactory.ResultType => typeof(void); public abstract TAwaitable CreateCompleted(); - object IAwaitableFactory.CreateCompleted(object result) + object IAwaitableFactory.CreateCompleted(object? result) { Debug.Assert(result == null); @@ -50,7 +51,7 @@ Expression IAwaitableFactory.CreateResultExpression(Expression awaitableExpressi return new AwaitExpression(awaitableExpression, this); } - bool IAwaitableFactory.TryGetResult(object awaitable, out object result) + bool IAwaitableFactory.TryGetResult(object awaitable, out object? result) { Debug.Assert(awaitable is TAwaitable); diff --git a/src/Moq/Async/AwaitableFactory`2.cs b/src/Moq/Async/AwaitableFactory`2.cs index a0476053e..0931da051 100644 --- a/src/Moq/Async/AwaitableFactory`2.cs +++ b/src/Moq/Async/AwaitableFactory`2.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; @@ -14,16 +15,18 @@ namespace Moq.Async /// for awaitables that produce a result when awaited. /// abstract class AwaitableFactory : IAwaitableFactory + where TAwaitable : notnull { public Type ResultType => typeof(TResult); public abstract TAwaitable CreateCompleted(TResult result); - object IAwaitableFactory.CreateCompleted(object result) + object IAwaitableFactory.CreateCompleted(object? result) { + // TODO: result should only be null if TResult is a nullable type. Debug.Assert(result is TResult || result == null); - return this.CreateCompleted((TResult)result); + return this.CreateCompleted((TResult)result!); } public abstract TAwaitable CreateFaulted(Exception exception); @@ -45,11 +48,15 @@ object IAwaitableFactory.CreateFaulted(IEnumerable exceptions) return this.CreateFaulted(exceptions); } +#if NULLABLE_REFERENCE_TYPES + public abstract bool TryGetResult(TAwaitable awaitable, [MaybeNullWhen(false)] out TResult result); +#else public abstract bool TryGetResult(TAwaitable awaitable, out TResult result); +#endif public abstract Expression CreateResultExpression(Expression awaitableExpression); - bool IAwaitableFactory.TryGetResult(object awaitable, out object result) + bool IAwaitableFactory.TryGetResult(object awaitable, out object? result) { Debug.Assert(awaitable is TAwaitable); diff --git a/src/Moq/Async/IAwaitableFactory.cs b/src/Moq/Async/IAwaitableFactory.cs index 8af39e826..633cea616 100644 --- a/src/Moq/Async/IAwaitableFactory.cs +++ b/src/Moq/Async/IAwaitableFactory.cs @@ -11,7 +11,7 @@ interface IAwaitableFactory { Type ResultType { get; } - object CreateCompleted(object result = null); + object CreateCompleted(object? result = null); object CreateFaulted(Exception exception); @@ -19,6 +19,6 @@ interface IAwaitableFactory Expression CreateResultExpression(Expression awaitableExpression); - bool TryGetResult(object awaitable, out object result); + bool TryGetResult(object awaitable, out object? result); } } diff --git a/src/Moq/Async/TaskFactory.cs b/src/Moq/Async/TaskFactory.cs index d43276181..303f7f820 100644 --- a/src/Moq/Async/TaskFactory.cs +++ b/src/Moq/Async/TaskFactory.cs @@ -19,7 +19,7 @@ sealed class TaskFactory : AwaitableFactory public override Task CreateCompleted() { - return Task.FromResult(default); + return Task.CompletedTask; } public override Task CreateFaulted(Exception exception) diff --git a/src/Moq/Async/TaskFactory`1.cs b/src/Moq/Async/TaskFactory`1.cs index 1c419e6f1..1baefd3ae 100644 --- a/src/Moq/Async/TaskFactory`1.cs +++ b/src/Moq/Async/TaskFactory`1.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Threading.Tasks; @@ -33,10 +34,14 @@ public override Expression CreateResultExpression(Expression awaitableExpression { return Expression.MakeMemberAccess( awaitableExpression, - typeof(Task).GetProperty(nameof(Task.Result))); + typeof(Task).GetProperty(nameof(Task.Result))!); } - public override bool TryGetResult(Task task, out TResult result) +#if NULLABLE_REFERENCE_TYPES + public override bool TryGetResult(Task task, [MaybeNullWhen(false)] out TResult result) +#else + public override bool TryGetResult(Task task, out TResult? result) +#endif { if (task.Status == TaskStatus.RanToCompletion) { diff --git a/src/Moq/Async/ValueTaskFactory`1.cs b/src/Moq/Async/ValueTaskFactory`1.cs index 53eaa60ed..e14ddca67 100644 --- a/src/Moq/Async/ValueTaskFactory`1.cs +++ b/src/Moq/Async/ValueTaskFactory`1.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Threading.Tasks; @@ -33,10 +34,14 @@ public override Expression CreateResultExpression(Expression awaitableExpression { return Expression.MakeMemberAccess( awaitableExpression, - typeof(ValueTask).GetProperty(nameof(ValueTask.Result))); + typeof(ValueTask).GetProperty(nameof(ValueTask.Result))!); } +#if NULLABLE_REFERENCE_TYPES + public override bool TryGetResult(ValueTask valueTask, [MaybeNullWhen(false)] out TResult result) +#else public override bool TryGetResult(ValueTask valueTask, out TResult result) +#endif { if (valueTask.IsCompletedSuccessfully) { diff --git a/src/Moq/Behaviors/RaiseEvent.cs b/src/Moq/Behaviors/RaiseEvent.cs index 8707b00ea..556f5d370 100644 --- a/src/Moq/Behaviors/RaiseEvent.cs +++ b/src/Moq/Behaviors/RaiseEvent.cs @@ -11,10 +11,10 @@ sealed class RaiseEvent : Behavior { Mock mock; LambdaExpression expression; - Delegate eventArgsFunc; - object[] eventArgsParams; + Delegate? eventArgsFunc; + object?[]? eventArgsParams; - public RaiseEvent(Mock mock, LambdaExpression expression, Delegate eventArgsFunc, object[] eventArgsParams) + public RaiseEvent(Mock mock, LambdaExpression expression, Delegate? eventArgsFunc, object?[]? eventArgsParams) { Debug.Assert(mock != null); Debug.Assert(expression != null); @@ -28,7 +28,7 @@ public RaiseEvent(Mock mock, LambdaExpression expression, Delegate eventArgsFunc public override void Execute(Invocation invocation) { - object[] args; + object?[] args; if (this.eventArgsParams != null) { @@ -36,14 +36,14 @@ public override void Execute(Invocation invocation) } else { - var argsFuncType = this.eventArgsFunc.GetType(); + var argsFuncType = this.eventArgsFunc!.GetType(); if (argsFuncType.IsGenericType && argsFuncType.GetGenericArguments().Length == 1) { - args = new object[] { this.mock.Object, this.eventArgsFunc.InvokePreserveStack() }; + args = new object?[] { this.mock.Object, this.eventArgsFunc.InvokePreserveStack() }; } else { - args = new object[] { this.mock.Object, this.eventArgsFunc.InvokePreserveStack(invocation.Arguments) }; + args = new object?[] { this.mock.Object, this.eventArgsFunc.InvokePreserveStack(invocation.Arguments) }; } } diff --git a/src/Moq/Behaviors/ReturnBaseOrDefaultValue.cs b/src/Moq/Behaviors/ReturnBaseOrDefaultValue.cs index 20b186817..7d604b96c 100644 --- a/src/Moq/Behaviors/ReturnBaseOrDefaultValue.cs +++ b/src/Moq/Behaviors/ReturnBaseOrDefaultValue.cs @@ -31,7 +31,7 @@ public override void Execute(Invocation invocation) var tryCallDefaultInterfaceImplementation = false; #endif - var declaringType = method.DeclaringType; + var declaringType = method.DeclaringType!; if (declaringType.IsInterface) { if (this.mock.MockedType.IsInterface) diff --git a/src/Moq/Behaviors/ReturnComputedValue.cs b/src/Moq/Behaviors/ReturnComputedValue.cs index 750debe60..363a2baf8 100644 --- a/src/Moq/Behaviors/ReturnComputedValue.cs +++ b/src/Moq/Behaviors/ReturnComputedValue.cs @@ -8,9 +8,9 @@ namespace Moq.Behaviors { sealed class ReturnComputedValue : Behavior { - readonly Func valueFactory; + readonly Func valueFactory; - public ReturnComputedValue(Func valueFactory) + public ReturnComputedValue(Func valueFactory) { Debug.Assert(valueFactory != null); diff --git a/src/Moq/Behaviors/ReturnValue.cs b/src/Moq/Behaviors/ReturnValue.cs index 8824ecd20..97c2ca601 100644 --- a/src/Moq/Behaviors/ReturnValue.cs +++ b/src/Moq/Behaviors/ReturnValue.cs @@ -5,14 +5,14 @@ namespace Moq.Behaviors { sealed class ReturnValue : Behavior { - readonly object value; + readonly object? value; - public ReturnValue(object value) + public ReturnValue(object? value) { this.value = value; } - public object Value => this.value; + public object? Value => this.value; public override void Execute(Invocation invocation) { diff --git a/src/Moq/Behaviors/ThrowComputedException.cs b/src/Moq/Behaviors/ThrowComputedException.cs index 8afdc72c7..b1404d991 100644 --- a/src/Moq/Behaviors/ThrowComputedException.cs +++ b/src/Moq/Behaviors/ThrowComputedException.cs @@ -8,9 +8,9 @@ namespace Moq.Behaviors { sealed class ThrowComputedException : Behavior { - readonly Func exceptionFactory; + readonly Func exceptionFactory; - public ThrowComputedException(Func exceptionFactory) + public ThrowComputedException(Func exceptionFactory) { Debug.Assert(exceptionFactory != null); @@ -19,6 +19,7 @@ public ThrowComputedException(Func exceptionFactory) public override void Execute(Invocation invocation) { + // TODO: Technically this permits `throw null` here. throw this.exceptionFactory.Invoke(invocation); } } diff --git a/src/Moq/Capture.cs b/src/Moq/Capture.cs index 0798bc94e..fd04d1441 100644 --- a/src/Moq/Capture.cs +++ b/src/Moq/Capture.cs @@ -76,7 +76,7 @@ public static T In(IList collection, Expression> predicate) public static T With(CaptureMatch match) { Match.Register(match); - return default(T); + return default(T)!; } } } diff --git a/src/Moq/Condition.cs b/src/Moq/Condition.cs index 70ab3b434..c245974a8 100644 --- a/src/Moq/Condition.cs +++ b/src/Moq/Condition.cs @@ -8,15 +8,15 @@ namespace Moq sealed class Condition { Func condition; - Action success; + Action? success; - public Condition(Func condition, Action success = null) + public Condition(Func condition, Action? success = null) { this.condition = condition; this.success = success; } - public bool IsTrue => this.condition?.Invoke() == true; + public bool IsTrue => this.condition.Invoke(); public void SetupEvaluatedSuccessfully() => this.success?.Invoke(); } diff --git a/src/Moq/DefaultValueProvider.cs b/src/Moq/DefaultValueProvider.cs index c2bb2b34b..290da47db 100644 --- a/src/Moq/DefaultValueProvider.cs +++ b/src/Moq/DefaultValueProvider.cs @@ -49,7 +49,7 @@ protected DefaultValueProvider() /// /// Implementations may assume that all parameters have valid, non-, non- values. /// - protected internal abstract object GetDefaultValue(Type type, Mock mock); + protected internal abstract object? GetDefaultValue(Type type, Mock mock); /// /// @@ -65,7 +65,7 @@ protected DefaultValueProvider() /// /// Implementations may assume that all parameters have valid, non-, non- values. /// - protected internal virtual object GetDefaultParameterValue(ParameterInfo parameter, Mock mock) + protected internal virtual object? GetDefaultParameterValue(ParameterInfo parameter, Mock mock) { Debug.Assert(parameter != null); Debug.Assert(parameter.ParameterType != typeof(void)); @@ -88,7 +88,7 @@ protected internal virtual object GetDefaultParameterValue(ParameterInfo paramet /// /// Implementations may assume that all parameters have valid, non-, non- values. /// - protected internal virtual object GetDefaultReturnValue(MethodInfo method, Mock mock) + protected internal virtual object? GetDefaultReturnValue(MethodInfo method, Mock mock) { Debug.Assert(method != null); Debug.Assert(method.ReturnType != typeof(void)); diff --git a/src/Moq/EmptyDefaultValueProvider.cs b/src/Moq/EmptyDefaultValueProvider.cs index 3f6e05242..42f282af8 100644 --- a/src/Moq/EmptyDefaultValueProvider.cs +++ b/src/Moq/EmptyDefaultValueProvider.cs @@ -28,7 +28,7 @@ internal EmptyDefaultValueProvider() static object CreateArray(Type type, Mock mock) { - var elementType = type.GetElementType(); + var elementType = type.GetElementType()!; var lengths = new int[type.GetArrayRank()]; return Array.CreateInstance(elementType, lengths); } @@ -57,7 +57,7 @@ static object CreateQueryableOf(Type type, Mock mock) return typeof(Queryable).GetMethods("AsQueryable") .Single(x => x.IsGenericMethod) .MakeGenericMethod(elementType) - .Invoke(null, new[] { array }); + .Invoke(null, new[] { array })!; } } } diff --git a/src/Moq/Evaluator.cs b/src/Moq/Evaluator.cs index fd9614a90..4ce3c4681 100644 --- a/src/Moq/Evaluator.cs +++ b/src/Moq/Evaluator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace Moq @@ -53,7 +54,10 @@ internal Expression Eval(Expression exp) return this.Visit(exp); } - public override Expression Visit(Expression exp) +#if NULLABLE_REFERENCE_TYPES + [return: NotNullIfNotNull("exp")] +#endif + public override Expression? Visit(Expression? exp) { if (exp == null) { @@ -85,7 +89,7 @@ static Expression Evaluate(Expression e) class Nominator : ExpressionVisitor { Func fnCanBeEvaluated; - HashSet candidates; + HashSet candidates = null!; bool cannotBeEvaluated; internal Nominator(Func fnCanBeEvaluated) @@ -100,7 +104,7 @@ internal HashSet Nominate(Expression expression) return this.candidates; } - public override Expression Visit(Expression expression) + public override Expression? Visit(Expression? expression) { if (expression != null && expression.NodeType != ExpressionType.Quote) { diff --git a/src/Moq/EventHandlerCollection.cs b/src/Moq/EventHandlerCollection.cs index ceb7be911..35749ec2f 100644 --- a/src/Moq/EventHandlerCollection.cs +++ b/src/Moq/EventHandlerCollection.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace Moq @@ -36,19 +37,31 @@ public void Remove(EventInfo @event, Delegate eventHandler) { lock (this.eventHandlers) { - this.eventHandlers[@event] = Delegate.Remove(this.TryGet(@event), eventHandler); + var resultingDelegate = Delegate.Remove(this.TryGet(@event), eventHandler); + if (resultingDelegate == null) + { + eventHandlers.Remove(@event); + } + else + { + eventHandlers[@event] = resultingDelegate; + } } } - public bool TryGet(EventInfo @event, out Delegate handlers) +#if NULLABLE_REFERENCE_TYPES + public bool TryGet(EventInfo @event, [NotNullWhen(true)] out Delegate? handlers) +#else + public bool TryGet(EventInfo @event, out Delegate? handlers) +#endif { lock (this.eventHandlers) { - return this.eventHandlers.TryGetValue(@event, out handlers) && handlers != null; + return this.eventHandlers.TryGetValue(@event, out handlers); } } - Delegate TryGet(EventInfo @event) + Delegate? TryGet(EventInfo @event) { return this.eventHandlers.TryGetValue(@event, out var handlers) ? handlers : null; } diff --git a/src/Moq/Expectation.cs b/src/Moq/Expectation.cs index 7557a7e37..c69f80533 100644 --- a/src/Moq/Expectation.cs +++ b/src/Moq/Expectation.cs @@ -2,6 +2,7 @@ // All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using Moq.Async; @@ -16,18 +17,23 @@ abstract class Expectation : IEquatable { public abstract LambdaExpression Expression { get; } - public virtual bool HasResultExpression(out IAwaitableFactory awaitableFactory) +#if NULLABLE_REFERENCE_TYPES + + public virtual bool HasResultExpression([NotNullWhen(true)] out IAwaitableFactory? awaitableFactory) +#else + public virtual bool HasResultExpression(out IAwaitableFactory? awaitableFactory) +#endif { awaitableFactory = null; return false; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Expectation other && this.Equals(other); } - public abstract bool Equals(Expectation other); + public abstract bool Equals(Expectation? other); public abstract override int GetHashCode(); diff --git a/src/Moq/ExpressionComparer.cs b/src/Moq/ExpressionComparer.cs index 940089a5f..3400f098d 100644 --- a/src/Moq/ExpressionComparer.cs +++ b/src/Moq/ExpressionComparer.cs @@ -21,7 +21,7 @@ sealed class ExpressionComparer : IEqualityComparer { } - public bool Equals(Expression x, Expression y) + public bool Equals(Expression? x, Expression? y) { if (object.ReferenceEquals(x, y)) { @@ -137,7 +137,7 @@ public bool Equals(Expression x, Expression y) public int GetHashCode(Expression obj) { - return obj == null ? 0 : obj.GetHashCode(); + return obj.GetHashCode(); } static bool Equals(ReadOnlyCollection x, ReadOnlyCollection y, Func comparer) diff --git a/src/Moq/ExpressionExtensions.cs b/src/Moq/ExpressionExtensions.cs index 1b2b324af..805a39272 100644 --- a/src/Moq/ExpressionExtensions.cs +++ b/src/Moq/ExpressionExtensions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Linq.Expressions; @@ -64,7 +65,11 @@ internal static TDelegate CompileUsingExpressionCompiler(this Express return ExpressionCompiler.Instance.Compile(expression); } - public static bool IsMatch(this Expression expression, out Match match) +#if NULLABLE_REFERENCE_TYPES + public static bool IsMatch(this Expression expression, [NotNullWhen(true)] out Match? match) +#else + public static bool IsMatch(this Expression expression, out Match? match) +#endif { if (expression is MatchExpression matchExpression) { @@ -262,6 +267,7 @@ void Split(Expression e, out Expression r /* remainder */, out MethodExpectation } else // This should be unreachable. { + // TODO: Should we throw here? method = null; } p = new MethodExpectation( @@ -286,7 +292,7 @@ void Split(Expression e, out Expression r /* remainder */, out MethodExpectation expression: Expression.Lambda( Expression.Invoke(parameter, arguments), parameter), - method: r.Type.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), + method: r.Type.GetMethod("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!, arguments); return; } @@ -321,7 +327,8 @@ void Split(Expression e, out Expression r /* remainder */, out MethodExpectation } else // This should be unreachable. { - method = null; + // TODO: Should we throw here? + method = null!; } p = new MethodExpectation( expression: Expression.Lambda( @@ -341,7 +348,7 @@ void Split(Expression e, out Expression r /* remainder */, out MethodExpectation bool IsResult(MemberInfo member, out IAwaitableFactory? awaitableFactory) { - var instanceType = member.DeclaringType; + var instanceType = member.DeclaringType!; awaitableFactory = AwaitableFactory.TryGet(instanceType); var returnType = member switch { @@ -363,7 +370,7 @@ internal static PropertyInfo GetReboundProperty(this MemberExpression expression // the expression. we attempt to correct this here by checking whether the type of the accessed object // has a property by the same name whose base definition equals the property in the expression; if so, // we "upgrade" to the derived property. - if (property.DeclaringType != expression.Expression.Type) + if (property.DeclaringType != expression.Expression!.Type) { var parameterTypes = new ParameterTypes(property.GetIndexParameters()); var derivedProperty = expression.Expression.Type diff --git a/src/Moq/ExpressionReconstructor.cs b/src/Moq/ExpressionReconstructor.cs index 27a9f529c..196fc8209 100644 --- a/src/Moq/ExpressionReconstructor.cs +++ b/src/Moq/ExpressionReconstructor.cs @@ -29,6 +29,6 @@ protected ExpressionReconstructor() /// /// The delegate for which to reconstruct a LINQ expression tree. /// Arguments to pass to a parameterized constructor of . (Optional.) - public abstract Expression> ReconstructExpression(Action action, object[] ctorArgs = null); + public abstract Expression> ReconstructExpression(Action action, object?[]? ctorArgs = null); } } diff --git a/src/Moq/Expressions/Visitors/ConstructorCallVisitor.cs b/src/Moq/Expressions/Visitors/ConstructorCallVisitor.cs index 1a4917138..627792521 100644 --- a/src/Moq/Expressions/Visitors/ConstructorCallVisitor.cs +++ b/src/Moq/Expressions/Visitors/ConstructorCallVisitor.cs @@ -2,6 +2,7 @@ // All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Linq.Expressions; @@ -36,13 +37,18 @@ public static object[] ExtractArgumentValues(LambdaExpression newExpression) return visitor.arguments; } - ConstructorInfo constructor; + ConstructorInfo? constructor; object[] arguments; - public override Expression Visit(Expression node) +#if NULLABLE_REFERENCE_TYPES + [return: NotNullIfNotNull("node")] +#endif + public override Expression? Visit(Expression? node) { - switch (node.NodeType) + switch (node?.NodeType) { + case null: + return null; case ExpressionType.Lambda: case ExpressionType.New: case ExpressionType.Quote: @@ -58,18 +64,15 @@ public override Expression Visit(Expression node) protected override Expression VisitNew(NewExpression node) { - if (node != null) - { - constructor = node.Constructor; + constructor = node.Constructor; - // Creates a lambda which uses the same argument expressions as the - // arguments contained in the NewExpression - var argumentExtractor = Expression.Lambda>( - Expression.NewArrayInit( - typeof(object), - node.Arguments.Select(a => Expression.Convert(a, typeof(object))))); - arguments = ExpressionCompiler.Instance.Compile(argumentExtractor).Invoke(); - } + // Creates a lambda which uses the same argument expressions as the + // arguments contained in the NewExpression + var argumentExtractor = Expression.Lambda>( + Expression.NewArrayInit( + typeof(object), + node.Arguments.Select(a => Expression.Convert(a, typeof(object))))); + arguments = ExpressionCompiler.Instance.Compile(argumentExtractor).Invoke(); return node; } } diff --git a/src/Moq/Expressions/Visitors/EvaluateCaptures.cs b/src/Moq/Expressions/Visitors/EvaluateCaptures.cs index 594729560..b44040be1 100644 --- a/src/Moq/Expressions/Visitors/EvaluateCaptures.cs +++ b/src/Moq/Expressions/Visitors/EvaluateCaptures.cs @@ -22,7 +22,7 @@ protected override Expression VisitMember(MemberExpression node) { if (node.Member is FieldInfo fi && node.Expression is ConstantExpression ce - && node.Member.DeclaringType.IsDefined(typeof(CompilerGeneratedAttribute))) + && fi.DeclaringType!.IsDefined(typeof(CompilerGeneratedAttribute))) { return Expression.Constant(fi.GetValue(ce.Value), node.Type); } diff --git a/src/Moq/Expressions/Visitors/UpgradePropertyAccessorMethods.cs b/src/Moq/Expressions/Visitors/UpgradePropertyAccessorMethods.cs index 62554952d..05d0645b9 100644 --- a/src/Moq/Expressions/Visitors/UpgradePropertyAccessorMethods.cs +++ b/src/Moq/Expressions/Visitors/UpgradePropertyAccessorMethods.cs @@ -48,7 +48,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) if (argumentCount == 0) { // getter: - var property = node.Method.DeclaringType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var property = node.Method.DeclaringType!.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Debug.Assert(property != null && property.GetGetMethod(true) == node.Method); return Expression.MakeMemberAccess(instance, property); @@ -58,10 +58,10 @@ protected override Expression VisitMethodCall(MethodCallExpression node) // indexer getter: var parameterTypes = node.Method.GetParameterTypes(); var argumentTypes = parameterTypes.ToArray(); - var indexer = node.Method.DeclaringType.GetProperty(name, node.Method.ReturnType, argumentTypes); + var indexer = node.Method.DeclaringType!.GetProperty(name, node.Method.ReturnType, argumentTypes); Debug.Assert(indexer != null && indexer.GetGetMethod(true) == node.Method); - return Expression.MakeIndex(instance, indexer, arguments); + return Expression.MakeIndex(instance!, indexer, arguments); } } else if (node.Method.IsSetAccessor()) @@ -72,7 +72,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) if (argumentCount == 1) { // setter: - var property = node.Method.DeclaringType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var property = node.Method.DeclaringType!.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); Debug.Assert(property != null && property.GetSetMethod(true) == node.Method); var value = node.Arguments[0]; @@ -83,12 +83,12 @@ protected override Expression VisitMethodCall(MethodCallExpression node) // indexer setter: var parameterTypes = node.Method.GetParameterTypes(); var argumentTypes = parameterTypes.Take(parameterTypes.Count - 1).ToArray(); - var indexer = node.Method.DeclaringType.GetProperty(name, parameterTypes.Last(), argumentTypes); + var indexer = node.Method.DeclaringType!.GetProperty(name, parameterTypes.Last(), argumentTypes); Debug.Assert(indexer != null && indexer.GetSetMethod(true) == node.Method); var indices = arguments.Take(argumentCount - 1); var value = arguments.Last(); - return Expression.Assign(Expression.MakeIndex(instance, indexer, indices), value); + return Expression.Assign(Expression.MakeIndex(instance!, indexer, indices), value); } } } diff --git a/src/Moq/Extensions.cs b/src/Moq/Extensions.cs index 0a920c72f..a33b61541 100644 --- a/src/Moq/Extensions.cs +++ b/src/Moq/Extensions.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -20,12 +21,20 @@ public static bool CanCreateInstance(this Type type) return type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null; } - public static bool CanRead(this PropertyInfo property, out MethodInfo getter) +#if NULLABLE_REFERENCE_TYPES + public static bool CanRead(this PropertyInfo property, [NotNullWhen(true)] out MethodInfo? getter) +#else + public static bool CanRead(this PropertyInfo property, out MethodInfo? getter) +#endif { return property.CanRead(out getter, out _); } - public static bool CanRead(this PropertyInfo property, out MethodInfo getter, out PropertyInfo getterProperty) +#if NULLABLE_REFERENCE_TYPES + public static bool CanRead(this PropertyInfo property, [NotNullWhen(true)] out MethodInfo? getter, [NotNullWhen(true)] out PropertyInfo? getterProperty) +#else + public static bool CanRead(this PropertyInfo property, out MethodInfo? getter, out PropertyInfo? getterProperty) +#endif { if (property.CanRead) { @@ -51,7 +60,7 @@ public static bool CanRead(this PropertyInfo property, out MethodInfo getter, ou var baseProperty = baseSetter .DeclaringType - .GetMember(property.Name, MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + !.GetMember(property.Name, MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Cast() .First(p => p.GetSetMethod(nonPublic: true) == baseSetter); return baseProperty.CanRead(out getter, out getterProperty); @@ -63,12 +72,21 @@ public static bool CanRead(this PropertyInfo property, out MethodInfo getter, ou return false; } - public static bool CanWrite(this PropertyInfo property, out MethodInfo setter) +#if NULLABLE_REFERENCE_TYPES + public static bool CanWrite(this PropertyInfo property, [NotNullWhen(true)] out MethodInfo? setter) +#else + public static bool CanWrite(this PropertyInfo property, out MethodInfo? setter) +#endif { return property.CanWrite(out setter, out _); } - public static bool CanWrite(this PropertyInfo property, out MethodInfo setter, out PropertyInfo setterProperty) +#if NULLABLE_REFERENCE_TYPES + public static bool CanWrite(this PropertyInfo property, [NotNullWhen(true)] out MethodInfo? setter, [NotNullWhen(true)] out PropertyInfo? setterProperty) + +#else + public static bool CanWrite(this PropertyInfo property, out MethodInfo? setter, out PropertyInfo? setterProperty) +#endif { if (property.CanWrite) { @@ -94,7 +112,7 @@ public static bool CanWrite(this PropertyInfo property, out MethodInfo setter, o var baseProperty = baseGetter .DeclaringType - .GetMember(property.Name, MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + !.GetMember(property.Name, MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Cast() .First(p => p.GetGetMethod(nonPublic: true) == baseGetter); return baseProperty.CanWrite(out setter, out setterProperty); @@ -109,7 +127,7 @@ public static bool CanWrite(this PropertyInfo property, out MethodInfo setter, o /// /// Gets the default value for the specified type. This is the Reflection counterpart of C#'s operator. /// - public static object GetDefaultValue(this Type type) + public static object? GetDefaultValue(this Type type) { return type.IsValueType ? Activator.CreateInstance(type) : null; } @@ -129,20 +147,20 @@ public static MethodInfo GetImplementingMethod(this MethodInfo method, Type prox method = method.GetGenericMethodDefinition(); } - var declaringType = method.DeclaringType; + var declaringType = method.DeclaringType!; if (declaringType.IsInterface) { Debug.Assert(declaringType.IsAssignableFrom(proxyType)); - var map = GetInterfaceMap(proxyType, method.DeclaringType); + var map = GetInterfaceMap(proxyType, declaringType); var index = Array.IndexOf(map.InterfaceMethods, method); Debug.Assert(index >= 0); return map.TargetMethods[index].GetBaseDefinition(); } else if (declaringType.IsDelegateType()) { - return proxyType.GetMethod("Invoke"); + return proxyType.GetMethod("Invoke")!; } else { @@ -152,15 +170,15 @@ public static MethodInfo GetImplementingMethod(this MethodInfo method, Type prox } } - public static object InvokePreserveStack(this Delegate del, IReadOnlyList args = null) + public static object? InvokePreserveStack(this Delegate del, IReadOnlyList? args = null) { try { - return del.DynamicInvoke((args as object[]) ?? args?.ToArray()); + return del.DynamicInvoke((args as object?[]) ?? args?.ToArray()); } catch (TargetInvocationException ex) { - ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + ExceptionDispatchInfo.Capture(ex.InnerException!).Throw(); throw; } } @@ -237,11 +255,15 @@ public static bool IsTypeMatcher(this Type type) return Attribute.IsDefined(type, typeof(TypeMatcherAttribute)); } - public static bool IsTypeMatcher(this Type type, out Type typeMatcherType) +#if NULLABLE_REFERENCE_TYPES + public static bool IsTypeMatcher(this Type type, [NotNullWhen(true)] out Type? typeMatcherType) +#else + public static bool IsTypeMatcher(this Type type, out Type? typeMatcherType) +#endif { if (type.IsTypeMatcher()) { - var attr = (TypeMatcherAttribute)Attribute.GetCustomAttribute(type, typeof(TypeMatcherAttribute)); + var attr = (TypeMatcherAttribute)Attribute.GetCustomAttribute(type, typeof(TypeMatcherAttribute))!; typeMatcherType = attr.Type ?? type; Guard.ImplementsTypeMatcherProtocol(typeMatcherType); return true; @@ -261,7 +283,7 @@ public static bool IsOrContainsTypeMatcher(this Type type) } else if (type.HasElementType) { - return type.GetElementType().IsOrContainsTypeMatcher(); + return type.GetElementType()!.IsOrContainsTypeMatcher(); } else if (type.IsGenericType) { @@ -373,7 +395,7 @@ public static bool CompareParameterTypesTo(this Delegate function, return false; } - static MethodInfo GetInvokeMethodFromUntypedDelegateCallback(Delegate callback) + static MethodInfo? GetInvokeMethodFromUntypedDelegateCallback(Delegate callback) { // Section 8.9.3 of 4th Ed ECMA 335 CLI spec requires delegates to have an 'Invoke' method. // However, there is not a requirement for 'public', or for it to be unambiguous. @@ -406,7 +428,7 @@ public static Type SubstituteTypeMatchers(this Type type, Type other) if (type.IsTypeMatcher(out var typeMatcherType)) { - var typeMatcher = (ITypeMatcher)Activator.CreateInstance(typeMatcherType); + var typeMatcher = (ITypeMatcher)Activator.CreateInstance(typeMatcherType)!; if (typeMatcher.Matches(other)) { @@ -415,8 +437,8 @@ public static Type SubstituteTypeMatchers(this Type type, Type other) } else if (type.HasElementType && other.HasElementType) { - var te = type.GetElementType(); - var oe = other.GetElementType(); + var te = type.GetElementType()!; + var oe = other.GetElementType()!; if (type.IsArray && other.IsArray) { @@ -487,11 +509,10 @@ static InterfaceMapping GetInterfaceMap(Type type, Type interfaceType) public static IEnumerable FindAllInnerMocks(this SetupCollection setups) { return setups.FindAll(setup => !setup.IsConditional) - .SelectMany(setup => setup.InnerMocks) - .Where(innerMock => innerMock != null); + .SelectMany(setup => setup.InnerMocks); } - public static Mock FindLastInnerMock(this SetupCollection setups, Func predicate) + public static Mock? FindLastInnerMock(this SetupCollection setups, Func predicate) { return setups.FindLast(setup => !setup.IsConditional && predicate(setup))?.InnerMocks.SingleOrDefault(); } diff --git a/src/Moq/Guard.cs b/src/Moq/Guard.cs index 77d658769..647c11dc1 100644 --- a/src/Moq/Guard.cs +++ b/src/Moq/Guard.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq.Expressions; using System.Reflection; @@ -28,7 +29,7 @@ public static void CanCreateInstance(Type type) } } - public static void ImplementsInterface(Type interfaceType, Type type, string paramName = null) + public static void ImplementsInterface(Type interfaceType, Type type, string? paramName = null) { Debug.Assert(interfaceType != null); Debug.Assert(interfaceType.IsInterface); @@ -92,7 +93,7 @@ public static void IsOverridable(MethodInfo method, Expression expression) string.Format( CultureInfo.CurrentCulture, method.IsExtensionMethod() ? Resources.UnsupportedExtensionMethod : Resources.UnsupportedStaticMember, - $"{method.DeclaringType.GetFormattedName()}.{method.Name}"))); + $"{method.DeclaringType!.GetFormattedName()}.{method.Name}"))); } else if (!method.CanOverride()) { @@ -104,18 +105,18 @@ public static void IsOverridable(MethodInfo method, Expression expression) string.Format( CultureInfo.CurrentCulture, Resources.UnsupportedNonOverridableMember, - $"{method.DeclaringType.GetFormattedName()}.{method.Name}"))); + $"{method.DeclaringType!.GetFormattedName()}.{method.Name}"))); } } public static void IsVisibleToProxyFactory(MethodInfo method) { - if (ProxyFactory.Instance.IsMethodVisible(method, out string messageIfNotVisible) == false) + if (ProxyFactory.Instance.IsMethodVisible(method, out string? messageIfNotVisible) == false) { throw new ArgumentException(string.Format( CultureInfo.CurrentCulture, Resources.MethodNotVisibleToProxyFactory, - method.DeclaringType.Name, + method.DeclaringType!.Name, method.Name, messageIfNotVisible)); } @@ -165,7 +166,11 @@ public static void IsEventRemove(LambdaExpression expression, string paramName) /// Ensures the given is not null. /// Throws otherwise. /// - public static void NotNull(object value, string paramName) +#if NULLABLE_REFERENCE_TYPES + public static void NotNull([NotNull] object? value, string paramName) +#else + public static void NotNull(object? value, string paramName) +#endif { if (value == null) { @@ -226,7 +231,7 @@ public static void CanRead(PropertyInfo property) throw new ArgumentException(string.Format( CultureInfo.CurrentCulture, Resources.PropertyGetNotFound, - property.DeclaringType.Name, property.Name)); + property.DeclaringType!.Name, property.Name)); } } @@ -237,7 +242,7 @@ public static void CanWrite(PropertyInfo property) throw new ArgumentException(string.Format( CultureInfo.CurrentCulture, Resources.PropertySetNotFound, - property.DeclaringType.Name, property.Name)); + property.DeclaringType!.Name, property.Name)); } } } diff --git a/src/Moq/IInvocation.cs b/src/Moq/IInvocation.cs index c2982b920..f543b5f26 100644 --- a/src/Moq/IInvocation.cs +++ b/src/Moq/IInvocation.cs @@ -20,12 +20,12 @@ public interface IInvocation /// /// Gets the arguments of the invocation. /// - IReadOnlyList Arguments { get; } + IReadOnlyList Arguments { get; } /// /// Gets the setup that matched this invocation (or if there was no matching setup). /// - ISetup MatchingSetup { get; } + ISetup? MatchingSetup { get; } /// /// Gets whether this invocation was successfully verified by any of the various `Verify` methods. @@ -35,11 +35,11 @@ public interface IInvocation /// /// The value being returned for a non-void method if no exception was thrown. /// - object ReturnValue { get; } + object? ReturnValue { get; } /// /// Optional exception if the method invocation results in an exception being thrown. /// - Exception Exception { get; } + Exception? Exception { get; } } } \ No newline at end of file diff --git a/src/Moq/IMatcher.cs b/src/Moq/IMatcher.cs index 1cd0dceef..e32c55ad5 100644 --- a/src/Moq/IMatcher.cs +++ b/src/Moq/IMatcher.cs @@ -7,8 +7,8 @@ namespace Moq { interface IMatcher { - bool Matches(object argument, Type parameterType); + bool Matches(object? argument, Type parameterType); - void SetupEvaluatedSuccessfully(object argument, Type parameterType); + void SetupEvaluatedSuccessfully(object? argument, Type parameterType); } } diff --git a/src/Moq/ISetup.cs b/src/Moq/ISetup.cs index 03255edba..9defbc549 100644 --- a/src/Moq/ISetup.cs +++ b/src/Moq/ISetup.cs @@ -49,7 +49,7 @@ public interface ISetup // /// The setup has more than one inner mock. // [Obsolete("Use 'InnerMocks' instead.")] // [EditorBrowsable(EditorBrowsableState.Never)] - Mock InnerMock { get; } + Mock? InnerMock { get; } // /// // /// Gets the inner mocks of this setup (if present and known). @@ -126,7 +126,7 @@ public interface ISetup /// e.g. by or by . /// /// - Expression OriginalExpression { get; } + Expression? OriginalExpression { get; } /// /// Verifies this setup and optionally all verifiable setups of its inner mock (if present and known). diff --git a/src/Moq/InnerMockSetup.cs b/src/Moq/InnerMockSetup.cs index ef7ed6e17..3eaef8cac 100644 --- a/src/Moq/InnerMockSetup.cs +++ b/src/Moq/InnerMockSetup.cs @@ -11,9 +11,9 @@ namespace Moq { sealed class InnerMockSetup : SetupWithOutParameterSupport { - readonly object returnValue; + readonly object? returnValue; - public InnerMockSetup(Expression originalExpression, Mock mock, MethodExpectation expectation, object returnValue) + public InnerMockSetup(Expression? originalExpression, Mock mock, MethodExpectation expectation, object? returnValue) : base(originalExpression, mock, expectation) { Debug.Assert(Awaitable.TryGetResultRecursive(returnValue) is IMocked); diff --git a/src/Moq/Interception/CastleProxyFactory.cs b/src/Moq/Interception/CastleProxyFactory.cs index 5bca46b2d..c17d9be42 100644 --- a/src/Moq/Interception/CastleProxyFactory.cs +++ b/src/Moq/Interception/CastleProxyFactory.cs @@ -44,7 +44,7 @@ ProxyGenerator GetClassGenerator(Type mockType) } /// - public override object CreateProxy(Type mockType, Moq.IInterceptor interceptor, Type[] interfaces, object[] arguments) + public override object CreateProxy(Type mockType, Moq.IInterceptor interceptor, Type[] interfaces, object?[] arguments) { // All generated proxies need to implement `IProxy`: var additionalInterfaces = new Type[1 + interfaces.Length]; @@ -62,7 +62,7 @@ public override object CreateProxy(Type mockType, Moq.IInterceptor interceptor, var options = new ProxyGenerationOptions(); options.AddDelegateTypeMixin(mockType); var container = GetClassGenerator(mockType).CreateClassProxy(typeof(object), additionalInterfaces, options, new Interceptor(interceptor)); - return Delegate.CreateDelegate(mockType, container, container.GetType().GetMethod("Invoke")); + return Delegate.CreateDelegate(mockType, container, container.GetType().GetMethod("Invoke")!); } try @@ -91,7 +91,7 @@ public override bool IsTypeVisible(Type type) sealed class Interceptor : Castle.DynamicProxy.IInterceptor { - static readonly MethodInfo proxyInterceptorGetter = typeof(IProxy).GetProperty(nameof(IProxy.Interceptor)).GetMethod; + static readonly MethodInfo proxyInterceptorGetter = typeof(IProxy).GetProperty(nameof(IProxy.Interceptor))!.GetMethod!; Moq.IInterceptor interceptor; @@ -129,7 +129,7 @@ public void Intercept(Castle.DynamicProxy.IInvocation underlying) sealed class Invocation : Moq.Invocation { - Castle.DynamicProxy.IInvocation underlying; + Castle.DynamicProxy.IInvocation? underlying; internal Invocation(Castle.DynamicProxy.IInvocation underlying) : base(underlying.Proxy.GetType(), underlying.Method, underlying.Arguments) { @@ -142,7 +142,7 @@ protected internal override object CallBase() #if FEATURE_DEFAULT_INTERFACE_IMPLEMENTATIONS var method = this.Method; - if (method.DeclaringType.IsInterface && !method.IsAbstract) + if (method.DeclaringType!.IsInterface && !method.IsAbstract) { // As of version 4.4.0, DynamicProxy cannot proceed to default method implementations of interfaces. // we need to find and call those manually. @@ -165,12 +165,12 @@ public void DetachFromUnderlying() // Finding and calling default interface implementations currently involves a lot of reflection, // we are using two caches to speed up these operations for repeated calls. static ConcurrentDictionary, MethodInfo> mostSpecificOverrides; - static ConcurrentDictionary> nonVirtualInvocationThunks; + static ConcurrentDictionary> nonVirtualInvocationThunks; static CastleProxyFactory() { mostSpecificOverrides = new ConcurrentDictionary, MethodInfo>(); - nonVirtualInvocationThunks = new ConcurrentDictionary>(); + nonVirtualInvocationThunks = new ConcurrentDictionary>(); } /// @@ -189,7 +189,7 @@ public static MethodInfo FindMostSpecificOverride(MethodInfo declaration, Type p var genericParameterCount = declaration.IsGenericMethod ? declaration.GetGenericArguments().Length : 0; var returnType = declaration.ReturnType; var parameterTypes = declaration.GetParameterTypes().ToArray(); - var declaringType = declaration.DeclaringType; + var declaringType = declaration.DeclaringType!; // If the base class has a method implementation, then by rule (2) it will be more specific // than any candidate method from an implemented interface: @@ -232,7 +232,7 @@ public static MethodInfo FindMostSpecificOverride(MethodInfo declaration, Type p // No, it is the most specific override so far. Add it to the list, but before doing so, // remove all less specific overrides from it: - candidateMethods.ExceptWith(candidateMethods.Where(cm => cm.DeclaringType.IsAssignableFrom(implementedInterface)).ToArray()); + candidateMethods.ExceptWith(candidateMethods.Where(cm => cm.DeclaringType!.IsAssignableFrom(implementedInterface)).ToArray()); candidateMethods.Add(candidateMethod); } @@ -256,7 +256,7 @@ public static MethodInfo FindMostSpecificOverride(MethodInfo declaration, Type p /// Performs a non-virtual (non-polymorphic) call to the given /// using the specified object and . /// - public static object DynamicInvokeNonVirtually(MethodInfo method, object instance, object[] arguments) + public static object DynamicInvokeNonVirtually(MethodInfo method, object instance, object?[] arguments) { // There are a couple of probable alternatives to the following implementation that // unfortunately don't work in practice: @@ -293,7 +293,7 @@ public static object DynamicInvokeNonVirtually(MethodInfo method, object instanc { if (parameterTypes[i].IsByRef) { - parameterTypes[i] = parameterTypes[i].GetElementType(); + parameterTypes[i] = parameterTypes[i].GetElementType()!; } } @@ -320,7 +320,7 @@ public static object DynamicInvokeNonVirtually(MethodInfo method, object instanc // Perform the actual call. il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, method.DeclaringType); + il.Emit(OpCodes.Castclass, method.DeclaringType!); for (var i = 0; i < n; ++i) { il.Emit(originalParameterTypes[i].IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, arguments[i]); @@ -355,7 +355,7 @@ public static object DynamicInvokeNonVirtually(MethodInfo method, object instanc il.Emit(OpCodes.Ldloc, returnValue); il.Emit(OpCodes.Ret); - return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); }); return thunk.Invoke(instance, arguments); diff --git a/src/Moq/Interception/InterceptionAspects.cs b/src/Moq/Interception/InterceptionAspects.cs index a3bf1b790..6b92f5e7c 100644 --- a/src/Moq/Interception/InterceptionAspects.cs +++ b/src/Moq/Interception/InterceptionAspects.cs @@ -117,7 +117,7 @@ public static bool Handle(Invocation invocation, Mock mock) if (methodName[0] == 'a' && methodName[3] == '_' && invocation.Method.IsEventAddAccessor()) { var implementingMethod = invocation.Method.GetImplementingMethod(invocation.ProxyType); - var @event = implementingMethod.DeclaringType.GetEvents(bindingFlags).SingleOrDefault(e => e.GetAddMethod(true) == implementingMethod); + var @event = implementingMethod.DeclaringType!.GetEvents(bindingFlags).SingleOrDefault(e => e.GetAddMethod(true) == implementingMethod); if (@event != null) { if (mock.CallBase && !invocation.Method.IsAbstract) @@ -135,7 +135,7 @@ public static bool Handle(Invocation invocation, Mock mock) else if (methodName[0] == 'r' && methodName.Length > 7 && methodName[6] == '_' && invocation.Method.IsEventRemoveAccessor()) { var implementingMethod = invocation.Method.GetImplementingMethod(invocation.ProxyType); - var @event = implementingMethod.DeclaringType.GetEvents(bindingFlags).SingleOrDefault(e => e.GetRemoveMethod(true) == implementingMethod); + var @event = implementingMethod.DeclaringType!.GetEvents(bindingFlags).SingleOrDefault(e => e.GetRemoveMethod(true) == implementingMethod); if (@event != null) { if (mock.CallBase && !invocation.Method.IsAbstract) diff --git a/src/Moq/Interception/InterfaceProxy.cs b/src/Moq/Interception/InterfaceProxy.cs index 2b3a272c9..3d8b91347 100644 --- a/src/Moq/Interception/InterfaceProxy.cs +++ b/src/Moq/Interception/InterfaceProxy.cs @@ -17,19 +17,19 @@ namespace Moq.Internals [EditorBrowsable(EditorBrowsableState.Never)] public abstract class InterfaceProxy { - static MethodInfo equalsMethod = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance); - static MethodInfo getHashCodeMethod = typeof(object).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance); - static MethodInfo toStringMethod = typeof(object).GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance); + static MethodInfo equalsMethod = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance)!; + static MethodInfo getHashCodeMethod = typeof(object).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance)!; + static MethodInfo toStringMethod = typeof(object).GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance)!; /// [DebuggerHidden] - public sealed override bool Equals(object obj) + public sealed override bool Equals(object? obj) { // Forward this call to the interceptor, so that `object.Equals` can be set up. var interceptor = (IInterceptor)((IProxy)this).Interceptor; var invocation = new Invocation(this.GetType(), equalsMethod, obj); interceptor.Intercept(invocation); - return (bool)invocation.ReturnValue; + return (bool)invocation.ReturnValue!; } /// @@ -40,25 +40,25 @@ public sealed override int GetHashCode() var interceptor = (IInterceptor)((IProxy)this).Interceptor; var invocation = new Invocation(this.GetType(), getHashCodeMethod); interceptor.Intercept(invocation); - return (int)invocation.ReturnValue; + return (int)invocation.ReturnValue!; } /// [DebuggerHidden] - public sealed override string ToString() + public sealed override string? ToString() { // Forward this call to the interceptor, so that `object.ToString` can be set up. var interceptor = (IInterceptor)((IProxy)this).Interceptor; var invocation = new Invocation(this.GetType(), toStringMethod); interceptor.Intercept(invocation); - return (string)invocation.ReturnValue; + return (string?)invocation.ReturnValue; } sealed class Invocation : Moq.Invocation { - static object[] noArguments = new object[0]; + static object?[] noArguments = new object?[0]; - public Invocation(Type proxyType, MethodInfo method, params object[] arguments) + public Invocation(Type proxyType, MethodInfo method, params object?[] arguments) : base(proxyType, method, arguments) { } diff --git a/src/Moq/Interception/ProxyFactory.cs b/src/Moq/Interception/ProxyFactory.cs index 6ad56f18c..ca35694b9 100644 --- a/src/Moq/Interception/ProxyFactory.cs +++ b/src/Moq/Interception/ProxyFactory.cs @@ -13,7 +13,7 @@ abstract class ProxyFactory /// public static ProxyFactory Instance { get; } = new CastleProxyFactory(); - public abstract object CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, object[] arguments); + public abstract object CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, object?[] arguments); public abstract bool IsMethodVisible(MethodInfo method, out string messageIfNotVisible); diff --git a/src/Moq/Invocation.cs b/src/Moq/Invocation.cs index 9b8a237f2..19a918c7c 100644 --- a/src/Moq/Invocation.cs +++ b/src/Moq/Invocation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; @@ -13,12 +14,12 @@ namespace Moq { abstract class Invocation : IInvocation { - object[] arguments; + object?[] arguments; MethodInfo method; - MethodInfo methodImplementation; + MethodInfo? methodImplementation; readonly Type proxyType; - object result; - Setup matchingSetup; + object? result; + Setup? matchingSetup; bool verified; /// @@ -27,7 +28,7 @@ abstract class Invocation : IInvocation /// The of the concrete proxy object on which a method is being invoked. /// The method being invoked. /// The arguments with which the specified is being invoked. - protected Invocation(Type proxyType, MethodInfo method, params object[] arguments) + protected Invocation(Type proxyType, MethodInfo method, params object?[] arguments) { Debug.Assert(proxyType != null); Debug.Assert(arguments != null); @@ -63,15 +64,15 @@ public MethodInfo MethodImplementation /// Arguments may be modified. Derived classes must ensure that by-reference parameters are written back /// when the invocation is ended by a call to any of the three Returns methods. /// - public object[] Arguments => this.arguments; + public object?[] Arguments => this.arguments; - IReadOnlyList IInvocation.Arguments => this.arguments; + IReadOnlyList IInvocation.Arguments => this.arguments; - public ISetup MatchingSetup => this.matchingSetup; + public ISetup? MatchingSetup => this.matchingSetup; public Type ProxyType => this.proxyType; - public object ReturnValue + public object? ReturnValue { get => this.result is ExceptionResult ? null : this.result; set @@ -80,8 +81,10 @@ public object ReturnValue this.result = value; } } - - public Exception Exception +#if NULLABLE_REFERENCE_TYPES + [DisallowNull] +#endif + public Exception? Exception { get => this.result is ExceptionResult r ? r.Exception : null; set @@ -134,7 +137,7 @@ public override string ToString() var method = this.Method; var builder = new StringBuilder(); - builder.AppendNameOf(method.DeclaringType); + builder.AppendNameOf(method.DeclaringType!); builder.Append('.'); if (method.IsGetAccessor()) diff --git a/src/Moq/InvocationCollection.cs b/src/Moq/InvocationCollection.cs index decfcd4cc..2783f2cb2 100644 --- a/src/Moq/InvocationCollection.cs +++ b/src/Moq/InvocationCollection.cs @@ -10,7 +10,7 @@ namespace Moq { sealed class InvocationCollection : IInvocationList { - Invocation[] invocations; + Invocation[] invocations = new Invocation[0]; int capacity = 0; int count = 0; @@ -72,7 +72,7 @@ public void Clear() lock (this.invocationsLock) { // Replace the collection so readers with a reference to the old collection aren't interrupted - this.invocations = null; + this.invocations = new Invocation[0]; this.count = 0; this.capacity = 0; diff --git a/src/Moq/It.cs b/src/Moq/It.cs index d6c81f237..1bfc9d996 100644 --- a/src/Moq/It.cs +++ b/src/Moq/It.cs @@ -32,7 +32,7 @@ public static class Ref /// /// Matches any value that is assignment-compatible with type . /// - public static TValue IsAny; + public static TValue IsAny = default(TValue)!; } /// @@ -64,7 +64,7 @@ public static TValue IsAny() } } - static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static); + static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static)!; internal static MethodCallExpression IsAny(Type genericArgument) { @@ -143,7 +143,7 @@ public static TValue Is(Expression> match) throw new ArgumentException(Resources.UseItIsOtherOverload, nameof(match)); } - var thisMethod = (MethodInfo)MethodBase.GetCurrentMethod(); + var thisMethod = (MethodInfo)MethodBase.GetCurrentMethod()!; var compiledMatchMethod = match.CompileUsingExpressionCompiler(); return Match.Create( @@ -165,9 +165,9 @@ public static TValue Is(Expression> match) /// Allows the specification of a predicate to perform matching of method call arguments. /// [EditorBrowsable(EditorBrowsableState.Advanced)] - public static TValue Is(Expression> match) + public static TValue Is(Expression> match) { - var thisMethod = (MethodInfo)MethodBase.GetCurrentMethod(); + var thisMethod = (MethodInfo)MethodBase.GetCurrentMethod()!; var compiledMatchMethod = match.CompileUsingExpressionCompiler(); return Match.Create( diff --git a/src/Moq/Language/Flow/SetupPhrase.cs b/src/Moq/Language/Flow/SetupPhrase.cs index e6409b9a6..dcbdff386 100644 --- a/src/Moq/Language/Flow/SetupPhrase.cs +++ b/src/Moq/Language/Flow/SetupPhrase.cs @@ -286,9 +286,9 @@ public void Verifiable(string failMessage) public void Verifiable(Times times) => this.Verifiable(times, null); - public void Verifiable(Func times, string failMessage) => this.Verifiable(times(), failMessage); + public void Verifiable(Func times, string? failMessage) => this.Verifiable(times(), failMessage); - public void Verifiable(Times times, string failMessage) + public void Verifiable(Times times, string? failMessage) { this.setup.MarkAsVerifiable(); this.setup.SetExpectedInvocationCount(times); diff --git a/src/Moq/Linq/MockSetupsBuilder.cs b/src/Moq/Linq/MockSetupsBuilder.cs index 77a946eeb..c73583486 100644 --- a/src/Moq/Linq/MockSetupsBuilder.cs +++ b/src/Moq/Linq/MockSetupsBuilder.cs @@ -103,7 +103,7 @@ protected override Expression VisitUnary(UnaryExpression node) return base.VisitUnary(node); } - static Expression ConvertToSetup(Expression left, Expression right) + static Expression? ConvertToSetup(Expression left, Expression right) { switch (left.NodeType) { diff --git a/src/Moq/LookupOrFallbackDefaultValueProvider.cs b/src/Moq/LookupOrFallbackDefaultValueProvider.cs index a5ea28548..173617047 100644 --- a/src/Moq/LookupOrFallbackDefaultValueProvider.cs +++ b/src/Moq/LookupOrFallbackDefaultValueProvider.cs @@ -34,14 +34,14 @@ namespace Moq [EditorBrowsable(EditorBrowsableState.Advanced)] public abstract class LookupOrFallbackDefaultValueProvider : DefaultValueProvider { - Dictionary> factories; + Dictionary?> factories; /// /// Initializes a new instance of the class. /// protected LookupOrFallbackDefaultValueProvider() { - this.factories = new Dictionary>() + this.factories = new Dictionary?>() { ["System.ValueTuple`1"] = CreateValueTupleOf, ["System.ValueTuple`2"] = CreateValueTupleOf, @@ -61,7 +61,7 @@ protected LookupOrFallbackDefaultValueProvider() /// The type(s) for which to remove any registered factory function. protected void Deregister(Type factoryKey) { - Debug.Assert(factoryKey != null); + Debug.Assert(factoryKey.FullName != null); // NOTE: In order to be able to unregister the default logic for awaitable types, // we need a way (below) to know when to delegate to an `IAwaitableFactory`, and when not to. @@ -93,7 +93,7 @@ protected void Register(Type factoryKey, Func factory) } /// - protected internal sealed override object GetDefaultParameterValue(ParameterInfo parameter, Mock mock) + protected internal sealed override object? GetDefaultParameterValue(ParameterInfo parameter, Mock mock) { Debug.Assert(parameter != null); Debug.Assert(parameter.ParameterType != typeof(void)); @@ -103,7 +103,7 @@ protected internal sealed override object GetDefaultParameterValue(ParameterInfo } /// - protected internal sealed override object GetDefaultReturnValue(MethodInfo method, Mock mock) + protected internal sealed override object? GetDefaultReturnValue(MethodInfo method, Mock mock) { Debug.Assert(method != null); Debug.Assert(method.ReturnType != typeof(void)); @@ -113,7 +113,7 @@ protected internal sealed override object GetDefaultReturnValue(MethodInfo metho } /// - protected internal sealed override object GetDefaultValue(Type type, Mock mock) + protected internal sealed override object? GetDefaultValue(Type type, Mock mock) { Debug.Assert(type != null); Debug.Assert(type != typeof(void)); @@ -123,8 +123,8 @@ protected internal sealed override object GetDefaultValue(Type type, Mock mock) : type.IsArray ? typeof(Array) : type; - Func factory; - if (this.factories.TryGetValue(handlerKey, out factory) || this.factories.TryGetValue(handlerKey.FullName, out factory)) + Func? factory; + if (this.factories.TryGetValue(handlerKey, out factory) || this.factories.TryGetValue(handlerKey.FullName!, out factory)) { if (factory != null) // This prevents delegation to an `IAwaitableFactory` for deregistered awaitable types; see note above. { @@ -147,7 +147,7 @@ protected internal sealed override object GetDefaultValue(Type type, Mock mock) /// /// The type of which to produce a value. /// The on which an unexpected invocation has occurred. - protected virtual object GetFallbackDefaultValue(Type type, Mock mock) + protected virtual object? GetFallbackDefaultValue(Type type, Mock mock) { Debug.Assert(type != null); Debug.Assert(type != typeof(void)); @@ -159,12 +159,12 @@ protected virtual object GetFallbackDefaultValue(Type type, Mock mock) object CreateValueTupleOf(Type type, Mock mock) { var itemTypes = type.GetGenericArguments(); - var items = new object[itemTypes.Length]; + var items = new object?[itemTypes.Length]; for (int i = 0, n = itemTypes.Length; i < n; ++i) { items[i] = this.GetDefaultValue(itemTypes[i], mock); } - return Activator.CreateInstance(type, items); + return Activator.CreateInstance(type, items)!; } } } diff --git a/src/Moq/Match.cs b/src/Moq/Match.cs index 00707390f..bcb089287 100644 --- a/src/Moq/Match.cs +++ b/src/Moq/Match.cs @@ -68,17 +68,18 @@ public abstract class Match : IMatcher /// internal static TValue Matcher() { - return default(TValue); + return default(TValue)!; } - internal abstract bool Matches(object argument, Type parameterType); + internal abstract bool Matches(object? argument, Type parameterType); - internal abstract void SetupEvaluatedSuccessfully(object argument, Type parameterType); + internal abstract void SetupEvaluatedSuccessfully(object? argument, Type parameterType); - bool IMatcher.Matches(object argument, Type parameterType) => this.Matches(argument, parameterType); + bool IMatcher.Matches(object? argument, Type parameterType) => this.Matches(argument, parameterType); - void IMatcher.SetupEvaluatedSuccessfully(object value, Type parameterType) => this.SetupEvaluatedSuccessfully(value, parameterType); + void IMatcher.SetupEvaluatedSuccessfully(object? value, Type parameterType) => this.SetupEvaluatedSuccessfully(value, parameterType); + // TODO: Consider making the constructor set this to avoid the nullable reference warning. internal Expression RenderExpression { get; set; } /// @@ -89,7 +90,7 @@ internal static TValue Matcher() public static T Create(Predicate condition) { Match.Register(new Match(condition, () => Matcher())); - return default(T); + return default(T)!; } /// @@ -104,7 +105,7 @@ public static T Create(Predicate condition) public static T Create(Predicate condition, Expression> renderExpression) { Match.Register(new Match(condition, renderExpression)); - return default(T); + return default(T)!; } /// @@ -125,13 +126,13 @@ public static T Create(Predicate condition, Expression> renderExpr /// /// A lambda representation of the matcher. /// - public static T Create(Func condition, Expression> renderExpression) + public static T Create(Func condition, Expression> renderExpression) { Guard.NotNull(condition, nameof(condition)); Guard.NotNull(renderExpression, nameof(renderExpression)); Match.Register(new MatchFactory(condition, renderExpression)); - return default(T); + return default(T)!; } internal static void Register(Match match) @@ -163,29 +164,29 @@ internal static void Register(Match match) public class Match : Match, IEquatable> { internal Predicate Condition { get; set; } - internal Action Success { get; set; } + internal Action? Success { get; set; } - internal Match(Predicate condition, Expression> renderExpression, Action success = null) + internal Match(Predicate condition, Expression> renderExpression, Action? success = null) { this.Condition = condition; this.RenderExpression = renderExpression.Body.Apply(EvaluateCaptures.Rewriter); this.Success = success; } - internal override bool Matches(object argument, Type parameterType) + internal override bool Matches(object? argument, Type parameterType) { - return CanCast(argument) && this.Condition((T)argument); + return CanCast(argument) && this.Condition((T)argument!); } - internal override void SetupEvaluatedSuccessfully(object argument, Type parameterType) + internal override void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); Debug.Assert(CanCast(argument)); - this.Success?.Invoke((T)argument); + this.Success?.Invoke((T)argument!); } - static bool CanCast(object value) + static bool CanCast(object? value) { if (value != null) { @@ -199,15 +200,19 @@ static bool CanCast(object value) } /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Match other && this.Equals(other); } /// - public bool Equals(Match other) + public bool Equals(Match? other) { - if (this.Condition == other.Condition) + if (other == null) + { + return false; + } + else if (this.Condition == other.Condition) { return true; } @@ -234,9 +239,9 @@ public bool Equals(Match other) sealed class MatchFactory : Match { - readonly Func condition; + readonly Func condition; - internal MatchFactory(Func condition, LambdaExpression renderExpression) + internal MatchFactory(Func condition, LambdaExpression renderExpression) { Debug.Assert(condition != null); Debug.Assert(renderExpression != null); @@ -245,18 +250,18 @@ internal MatchFactory(Func condition, LambdaExpression rende this.RenderExpression = renderExpression.Body.Apply(EvaluateCaptures.Rewriter); } - internal override bool Matches(object argument, Type parameterType) + internal override bool Matches(object? argument, Type parameterType) { - var canCast = (Predicate)Delegate.CreateDelegate(typeof(Predicate), canCastMethod.MakeGenericMethod(parameterType)); + var canCast = (Predicate)Delegate.CreateDelegate(typeof(Predicate), canCastMethod.MakeGenericMethod(parameterType)); return canCast(argument) && condition(argument, parameterType); } - internal override void SetupEvaluatedSuccessfully(object argument, Type parameterType) + internal override void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } - static bool CanCast(object value) + static bool CanCast(object? value) { if (value != null) { @@ -269,7 +274,7 @@ static bool CanCast(object value) } } - static readonly MethodInfo canCastMethod = typeof(MatchFactory).GetMethod("CanCast", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly); + static readonly MethodInfo canCastMethod = typeof(MatchFactory).GetMethod(nameof(CanCast), BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!; // TODO: Check whether we need to implement `IEquatable<>` to make this work with delegate-based // setup & verification methods such as `SetupSet`! diff --git a/src/Moq/MatcherFactory.cs b/src/Moq/MatcherFactory.cs index 6c6484615..b11476092 100644 --- a/src/Moq/MatcherFactory.cs +++ b/src/Moq/MatcherFactory.cs @@ -52,7 +52,7 @@ public static Pair CreateMatcher(Expression argument, Para var member = memberExpression.Member; if (member.Name == nameof(It.Ref.IsAny)) { - var memberDeclaringType = member.DeclaringType; + var memberDeclaringType = member.DeclaringType!; if (memberDeclaringType.IsGenericType) { var memberDeclaringTypeDefinition = memberDeclaringType.GetGenericTypeDefinition(); @@ -77,7 +77,7 @@ public static Pair CreateMatcher(Expression argument, Para var newArrayExpression = (NewArrayExpression)argument; Debug.Assert(newArrayExpression.Type.IsArray); - var elementType = newArrayExpression.Type.GetElementType(); + var elementType = newArrayExpression.Type.GetElementType()!; var n = newArrayExpression.Expressions.Count; var matchers = new IMatcher[n]; diff --git a/src/Moq/MatcherObserver.cs b/src/Moq/MatcherObserver.cs index 41c8e32f1..e30c3692d 100644 --- a/src/Moq/MatcherObserver.cs +++ b/src/Moq/MatcherObserver.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Moq @@ -21,7 +22,7 @@ namespace Moq sealed class MatcherObserver : IDisposable { [ThreadStatic] - static Stack activations; + static Stack? activations; public static MatcherObserver Activate() { @@ -37,7 +38,11 @@ public static MatcherObserver Activate() return activation; } - public static bool IsActive(out MatcherObserver observer) +#if NULLABLE_REFERENCE_TYPES + public static bool IsActive([NotNullWhen(true)] out MatcherObserver? observer) +#else + public static bool IsActive(out MatcherObserver? observer) +#endif { var activations = MatcherObserver.activations; @@ -54,7 +59,7 @@ public static bool IsActive(out MatcherObserver observer) } int timestamp; - List observations; + List? observations; MatcherObserver() { @@ -94,7 +99,11 @@ public void OnMatch(Match match) /// and if so, returns the last one. /// /// The observed matcher observed last. - public bool TryGetLastMatch(out Match match) +#if NULLABLE_REFERENCE_TYPES + public bool TryGetLastMatch([NotNullWhen(true)] out Match? match) +#else + public bool TryGetLastMatch(out Match? match) +#endif { if (this.observations != null && this.observations.Count > 0) { diff --git a/src/Moq/Matchers/AnyMatcher.cs b/src/Moq/Matchers/AnyMatcher.cs index 11135338c..e7680e4e8 100644 --- a/src/Moq/Matchers/AnyMatcher.cs +++ b/src/Moq/Matchers/AnyMatcher.cs @@ -14,9 +14,9 @@ sealed class AnyMatcher : IMatcher { } - public bool Matches(object argument, Type parameterType) => true; + public bool Matches(object? argument, Type parameterType) => true; - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } diff --git a/src/Moq/Matchers/ConstantMatcher.cs b/src/Moq/Matchers/ConstantMatcher.cs index f43a2e84e..eb8aa06ba 100644 --- a/src/Moq/Matchers/ConstantMatcher.cs +++ b/src/Moq/Matchers/ConstantMatcher.cs @@ -10,14 +10,14 @@ namespace Moq.Matchers { class ConstantMatcher : IMatcher { - object constantValue; + object? constantValue; - public ConstantMatcher(object constantValue) + public ConstantMatcher(object? constantValue) { this.constantValue = constantValue; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { if (object.Equals(argument, constantValue)) { @@ -36,14 +36,14 @@ public bool Matches(object argument, Type parameterType) return false; } - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } bool MatchesEnumerable(IEnumerable enumerable) { - var constValues = (IEnumerable)constantValue; + var constValues = (IEnumerable)constantValue!; return constValues.Cast().SequenceEqual(enumerable.Cast()); } } diff --git a/src/Moq/Matchers/ExpressionMatcher.cs b/src/Moq/Matchers/ExpressionMatcher.cs index 72b910a82..7cd11e52e 100644 --- a/src/Moq/Matchers/ExpressionMatcher.cs +++ b/src/Moq/Matchers/ExpressionMatcher.cs @@ -16,13 +16,13 @@ public ExpressionMatcher(Expression expression) this.expression = expression; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { return argument is Expression valueExpression && ExpressionComparer.Default.Equals(this.expression, valueExpression); } - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } diff --git a/src/Moq/Matchers/LazyEvalMatcher.cs b/src/Moq/Matchers/LazyEvalMatcher.cs index 3f5fc8cfc..f8d2e2948 100644 --- a/src/Moq/Matchers/LazyEvalMatcher.cs +++ b/src/Moq/Matchers/LazyEvalMatcher.cs @@ -16,13 +16,13 @@ public LazyEvalMatcher(Expression expression) this.expression = expression; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { var eval = Evaluator.PartialEval(this.expression); return eval is ConstantExpression ce && new ConstantMatcher(ce.Value).Matches(argument, parameterType); } - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } diff --git a/src/Moq/Matchers/MatcherAttributeMatcher.cs b/src/Moq/Matchers/MatcherAttributeMatcher.cs index 1ce03f04c..1cd0f7bc7 100644 --- a/src/Moq/Matchers/MatcherAttributeMatcher.cs +++ b/src/Moq/Matchers/MatcherAttributeMatcher.cs @@ -43,7 +43,7 @@ static MethodInfo ResolveValidatorMethod(MethodCallExpression call) { var expectedParametersTypes = new[] { call.Method.ReturnType }.Concat(call.Method.GetParameters().Select(p => p.ParameterType)).ToArray(); - MethodInfo method = null; + MethodInfo? method; if (call.Method.IsGenericMethod) { @@ -51,7 +51,7 @@ static MethodInfo ResolveValidatorMethod(MethodCallExpression call) // passing generic type arguments for the query. var genericArgs = call.Method.GetGenericArguments(); - method = call.Method.DeclaringType.GetMethods(call.Method.Name) + method = call.Method.DeclaringType!.GetMethods(call.Method.Name) .Where(m => m.IsGenericMethodDefinition && m.GetGenericArguments().Length == @@ -63,7 +63,7 @@ static MethodInfo ResolveValidatorMethod(MethodCallExpression call) } else { - method = call.Method.DeclaringType.GetMethod(call.Method.Name, expectedParametersTypes); + method = call.Method.DeclaringType!.GetMethod(call.Method.Name, expectedParametersTypes); } // throw if validatorMethod doesn't exists @@ -74,22 +74,22 @@ static MethodInfo ResolveValidatorMethod(MethodCallExpression call) call.Method.IsStatic ? "static " : String.Empty, call.Method.Name, String.Join(", ", expectedParametersTypes.Select(x => x.Name).ToArray()), - call.Method.DeclaringType.ToString())); + call.Method.DeclaringType!.ToString())); } return method; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { // use matcher Expression to get extra arguments var extraArgs = this.expression.Arguments.Select(ae => ((ConstantExpression)ae.PartialEval()).Value); var args = new[] { argument }.Concat(extraArgs).ToArray(); // for static and non-static method - var instance = this.expression.Object == null ? null : (this.expression.Object.PartialEval() as ConstantExpression).Value; - return (bool)validatorMethod.Invoke(instance, args); + var instance = this.expression.Object == null ? null : ((ConstantExpression)this.expression.Object.PartialEval()).Value; + return (bool)validatorMethod.Invoke(instance, args)!; } - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); } diff --git a/src/Moq/Matchers/ParamArrayMatcher.cs b/src/Moq/Matchers/ParamArrayMatcher.cs index 4f1a2f46e..a65b2ee75 100644 --- a/src/Moq/Matchers/ParamArrayMatcher.cs +++ b/src/Moq/Matchers/ParamArrayMatcher.cs @@ -17,14 +17,14 @@ public ParamArrayMatcher(IMatcher[] matchers) this.matchers = matchers; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { if (argument is not Array values || this.matchers.Length != values.Length) { return false; } - var elementType = parameterType.GetElementType(); + var elementType = parameterType.GetElementType()!; for (int index = 0; index < values.Length; index++) { @@ -37,13 +37,13 @@ public bool Matches(object argument, Type parameterType) return true; } - public void SetupEvaluatedSuccessfully(object argument, Type parameterType) + public void SetupEvaluatedSuccessfully(object? argument, Type parameterType) { Debug.Assert(this.Matches(argument, parameterType)); Debug.Assert(argument is Array array && array.Length == this.matchers.Length); var values = (Array)argument; - var elementType = parameterType.GetElementType(); + var elementType = parameterType.GetElementType()!; for (int i = 0, n = this.matchers.Length; i < n; ++i) { this.matchers[i].SetupEvaluatedSuccessfully(values.GetValue(i), elementType); diff --git a/src/Moq/Matchers/RefMatcher.cs b/src/Moq/Matchers/RefMatcher.cs index 1d3efec67..effb206ef 100644 --- a/src/Moq/Matchers/RefMatcher.cs +++ b/src/Moq/Matchers/RefMatcher.cs @@ -8,22 +8,22 @@ namespace Moq.Matchers { class RefMatcher : IMatcher { - readonly object reference; + readonly object? reference; readonly bool referenceIsValueType; - public RefMatcher(object reference) + public RefMatcher(object? reference) { this.reference = reference; this.referenceIsValueType = reference?.GetType().IsValueType ?? false; } - public bool Matches(object argument, Type parameterType) + public bool Matches(object? argument, Type parameterType) { return this.referenceIsValueType ? object.Equals(this.reference, argument) : object.ReferenceEquals(this.reference, argument); } - public void SetupEvaluatedSuccessfully(object value, Type parameterType) + public void SetupEvaluatedSuccessfully(object? value, Type parameterType) { Debug.Assert(this.Matches(value, parameterType)); } diff --git a/src/Moq/MethodCall.cs b/src/Moq/MethodCall.cs index ffe4ce15d..2cf489fd8 100644 --- a/src/Moq/MethodCall.cs +++ b/src/Moq/MethodCall.cs @@ -20,16 +20,16 @@ namespace Moq { sealed partial class MethodCall : SetupWithOutParameterSupport { - VerifyInvocationCount verifyInvocationCount; - Behavior callback; - Behavior raiseEvent; - Behavior returnOrThrow; - Behavior afterReturnCallback; - Condition condition; - string failMessage; - string declarationSite; - - public MethodCall(Expression originalExpression, Mock mock, Condition condition, MethodExpectation expectation) + VerifyInvocationCount? verifyInvocationCount; + Behavior? callback; + Behavior? raiseEvent; + Behavior? returnOrThrow; + Behavior? afterReturnCallback; + Condition? condition; + string? failMessage; + string? declarationSite; + + public MethodCall(Expression originalExpression, Mock mock, Condition? condition, MethodExpectation expectation) : base(originalExpression, mock, expectation) { this.condition = condition; @@ -40,12 +40,12 @@ public MethodCall(Expression originalExpression, Mock mock, Condition condition, } } - public string FailMessage + public string? FailMessage { get => this.failMessage; } - public override Condition Condition => this.condition; + public override Condition? Condition => this.condition; public override IEnumerable InnerMocks { @@ -59,7 +59,7 @@ public override IEnumerable InnerMocks } } - static string GetUserCodeCallSite() + static string? GetUserCodeCallSite() { try { @@ -68,14 +68,14 @@ static string GetUserCodeCallSite() var frame = new StackTrace(true) .GetFrames() .SkipWhile(f => f.GetMethod() != thisMethod) - .SkipWhile(f => f.GetMethod().DeclaringType == null || f.GetMethod().DeclaringType.Assembly == mockAssembly) + .SkipWhile(f => f.GetMethod()!.DeclaringType == null || f.GetMethod()!.DeclaringType!.Assembly == mockAssembly) .FirstOrDefault(); var member = frame?.GetMethod(); if (member != null) { var declaredAt = new StringBuilder(); - declaredAt.AppendNameOf(member.DeclaringType).Append('.').AppendNameOf(member, false); - var fileName = Path.GetFileName(frame.GetFileName()); + declaredAt.AppendNameOf(member.DeclaringType!).Append('.').AppendNameOf(member, false); + var fileName = Path.GetFileName(frame!.GetFileName()); if (fileName != null) { declaredAt.Append(" in ").Append(fileName); @@ -144,7 +144,7 @@ public void SetCallbackBehavior(Delegate callback) throw new ArgumentNullException(nameof(callback)); } - ref Behavior behavior = ref (this.returnOrThrow == null) ? ref this.callback + ref Behavior? behavior = ref (this.returnOrThrow == null) ? ref this.callback : ref this.afterReturnCallback; if (callback is Action callbackWithoutArguments) @@ -224,7 +224,7 @@ public void SetReturnValueBehavior(object value) this.returnOrThrow = new ReturnValue(value); } - public void SetReturnComputedValueBehavior(Delegate valueFactory) + public void SetReturnComputedValueBehavior(Delegate? valueFactory) { Debug.Assert(this.Method.ReturnType != typeof(void)); Debug.Assert(this.returnOrThrow == null); @@ -302,7 +302,7 @@ public void SetThrowExceptionBehavior(Exception exception) this.returnOrThrow = new ThrowException(exception); } - public void SetThrowComputedExceptionBehavior(Delegate exceptionFactory) + public void SetThrowComputedExceptionBehavior(Delegate? exceptionFactory) { Debug.Assert(this.returnOrThrow == null); @@ -314,6 +314,7 @@ public void SetThrowComputedExceptionBehavior(Delegate exceptionFactory) // and instead of in `Throws(TException)`, we ended up in `Throws(Delegate)` or `Throws(Func)`, // which likely isn't what the user intended. // So here we do what we would've done in `Throws(TException)`: + // TODO: ThrowException expects non-null argument. this.returnOrThrow = new ThrowException(default); } else diff --git a/src/Moq/MethodExpectation.cs b/src/Moq/MethodExpectation.cs index 4112a4c10..9b3af6828 100644 --- a/src/Moq/MethodExpectation.cs +++ b/src/Moq/MethodExpectation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -38,14 +39,14 @@ public static MethodExpectation CreateFrom(Invocation invocation) for (int i = 0; i < n; ++i) { var parameterType = parameterTypes[i]; - if (parameterType.IsByRef) parameterType = parameterType.GetElementType(); + if (parameterType.IsByRef) parameterType = parameterType.GetElementType()!; arguments[i] = E.Constant(invocation.Arguments[i], parameterType); } } LambdaExpression expression; { - var mock = E.Parameter(method.DeclaringType, "mock"); + var mock = E.Parameter(method.DeclaringType!, "mock"); expression = E.Lambda(E.Call(mock, method, arguments).Apply(UpgradePropertyAccessorMethods.Rewriter), mock); } @@ -68,16 +69,16 @@ public static MethodExpectation CreateFrom(Invocation invocation) public readonly IReadOnlyList Arguments; readonly IMatcher[] argumentMatchers; - IAwaitableFactory awaitableFactory; - MethodInfo methodImplementation; - Expression[] partiallyEvaluatedArguments; + IAwaitableFactory? awaitableFactory; + MethodInfo? methodImplementation; + Expression[]? partiallyEvaluatedArguments; #if DEBUG - Type proxyType; + Type? proxyType; #endif readonly bool exactGenericTypeArguments; - public MethodExpectation(LambdaExpression expression, MethodInfo method, IReadOnlyList arguments = null, bool exactGenericTypeArguments = false, bool skipMatcherInitialization = false, bool allowNonOverridable = false) + public MethodExpectation(LambdaExpression expression, MethodInfo method, IReadOnlyList? arguments = null, bool exactGenericTypeArguments = false, bool skipMatcherInitialization = false, bool allowNonOverridable = false) { Debug.Assert(expression != null); Debug.Assert(method != null); @@ -111,7 +112,11 @@ public void AddResultExpression(Func add, IAwaitableFactory awaitableFacto this.awaitableFactory = awaitableFactory; } - public override bool HasResultExpression(out IAwaitableFactory awaitableFactory) +#if NULLABLE_REFERENCE_TYPES + public override bool HasResultExpression([NotNullWhen(true)] out IAwaitableFactory? awaitableFactory) +#else + public override bool HasResultExpression(out IAwaitableFactory? awaitableFactory) +#endif { return (awaitableFactory = this.awaitableFactory) != null; } @@ -199,7 +204,7 @@ bool IsOverride(Invocation invocation) return true; } - public override bool Equals(Expectation obj) + public override bool Equals(Expectation? obj) { if (obj is not MethodExpectation other) return false; diff --git a/src/Moq/MethodSetup.cs b/src/Moq/MethodSetup.cs index c6bb2b4fb..19fdee19c 100644 --- a/src/Moq/MethodSetup.cs +++ b/src/Moq/MethodSetup.cs @@ -11,7 +11,7 @@ namespace Moq /// abstract class MethodSetup : Setup { - protected MethodSetup(Expression originalExpression, Mock mock, MethodExpectation expectation) + protected MethodSetup(Expression? originalExpression, Mock mock, MethodExpectation expectation) : base(originalExpression, mock, expectation) { } diff --git a/src/Moq/Mock.cs b/src/Moq/Mock.cs index 958494f17..e4cea94a4 100644 --- a/src/Moq/Mock.cs +++ b/src/Moq/Mock.cs @@ -23,7 +23,7 @@ namespace Moq public abstract partial class Mock : IFluentInterface { internal static readonly MethodInfo GetMethod = - typeof(Mock).GetMethod(nameof(Get), BindingFlags.Public | BindingFlags.Static); + typeof(Mock).GetMethod(nameof(Get), BindingFlags.Public | BindingFlags.Static)!; /// /// Initializes a new instance of the class. @@ -151,7 +151,7 @@ public static void VerifyAll(params Mock[] mocks) /// public abstract bool CallBase { get; set; } - internal abstract object[] ConstructorArguments { get; } + internal abstract object?[] ConstructorArguments { get; } /// /// Specifies the behavior to use when returning default values for unexpected invocations on loose mocks. @@ -313,7 +313,7 @@ internal void Verify(Func predicate, HashSet verifiedMocks) } } - internal static void Verify(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static void Verify(Mock mock, LambdaExpression expression, Times times, string? failMessage) { Guard.NotNull(times, nameof(times)); @@ -333,7 +333,7 @@ internal static void Verify(Mock mock, LambdaExpression expression, Times times, } } - internal static void VerifyGet(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static void VerifyGet(Mock mock, LambdaExpression expression, Times times, string? failMessage) { Guard.NotNull(expression, nameof(expression)); @@ -346,7 +346,7 @@ internal static void VerifyGet(Mock mock, LambdaExpression expression, Times tim Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifySet(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static void VerifySet(Mock mock, LambdaExpression expression, Times times, string? failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsAssignmentToPropertyOrIndexer(expression, nameof(expression)); @@ -354,7 +354,7 @@ internal static void VerifySet(Mock mock, LambdaExpression expression, Times tim Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifyAdd(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static void VerifyAdd(Mock mock, LambdaExpression expression, Times times, string? failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventAdd(expression, nameof(expression)); @@ -362,7 +362,7 @@ internal static void VerifyAdd(Mock mock, LambdaExpression expression, Times tim Mock.Verify(mock, expression, times, failMessage); } - internal static void VerifyRemove(Mock mock, LambdaExpression expression, Times times, string failMessage) + internal static void VerifyRemove(Mock mock, LambdaExpression expression, Times times, string? failMessage) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventRemove(expression, nameof(expression)); @@ -379,7 +379,7 @@ static void VerifyNoOtherCalls(Mock mock, HashSet verifiedMocks) { if (!verifiedMocks.Add(mock)) return; - var unverifiedInvocations = mock.MutableInvocations.ToArray(invocation => !invocation.IsVerified); + Invocation?[] unverifiedInvocations = mock.MutableInvocations.ToArray(invocation => !invocation.IsVerified); var innerMocks = mock.MutableSetups.FindAllInnerMocks(); @@ -397,7 +397,7 @@ static void VerifyNoOtherCalls(Mock mock, HashSet verifiedMocks) // In order for an invocation to be "transitive", its return value has to be a // sub-object (inner mock); and that sub-object has to have received at least // one call: - var wasTransitiveInvocation = mock.MutableSetups.FindLastInnerMock(setup => setup.Matches(unverifiedInvocations[i])) is Mock innerMock + var wasTransitiveInvocation = mock.MutableSetups.FindLastInnerMock(setup => setup.Matches(unverifiedInvocations[i]!)) is Mock innerMock && innerMock.MutableInvocations.Any(); if (wasTransitiveInvocation) { @@ -410,7 +410,7 @@ static void VerifyNoOtherCalls(Mock mock, HashSet verifiedMocks) var remainingUnverifiedInvocations = unverifiedInvocations.Where(i => i != null); if (remainingUnverifiedInvocations.Any()) { - throw MockException.UnverifiedInvocations(mock, remainingUnverifiedInvocations); + throw MockException.UnverifiedInvocations(mock, remainingUnverifiedInvocations!); } } @@ -493,7 +493,7 @@ static int GetMatchingInvocationCount( #region Setup - internal static MethodCall Setup(Mock mock, LambdaExpression expression, Condition condition) + internal static MethodCall Setup(Mock mock, LambdaExpression expression, Condition? condition) { Guard.NotNull(expression, nameof(expression)); @@ -505,7 +505,7 @@ internal static MethodCall Setup(Mock mock, LambdaExpression expression, Conditi }); } - internal static MethodCall SetupGet(Mock mock, LambdaExpression expression, Condition condition) + internal static MethodCall SetupGet(Mock mock, LambdaExpression expression, Condition? condition) { Guard.NotNull(expression, nameof(expression)); @@ -518,7 +518,7 @@ internal static MethodCall SetupGet(Mock mock, LambdaExpression expression, Cond return Mock.Setup(mock, expression, condition); } - internal static MethodCall SetupSet(Mock mock, LambdaExpression expression, Condition condition) + internal static MethodCall SetupSet(Mock mock, LambdaExpression expression, Condition? condition) { Guard.NotNull(expression, nameof(expression)); Guard.IsAssignmentToPropertyOrIndexer(expression, nameof(expression)); @@ -527,7 +527,7 @@ internal static MethodCall SetupSet(Mock mock, LambdaExpression expression, Cond } internal static readonly MethodInfo SetupReturnsMethod = - typeof(Mock).GetMethod(nameof(SetupReturns), BindingFlags.NonPublic | BindingFlags.Static); + typeof(Mock).GetMethod(nameof(SetupReturns), BindingFlags.NonPublic | BindingFlags.Static)!; // This specialized setup method is used to set up a single `Mock.Of` predicate. // Unlike other setup methods, LINQ to Mocks can set non-interceptable properties, which is handy when initializing DTOs. @@ -535,7 +535,7 @@ internal static bool SetupReturns(Mock mock, LambdaExpression expression, object { Guard.NotNull(expression, nameof(expression)); - Mock.SetupRecursive(mock, expression, setupLast: (targetMock, oe, part) => + Mock.SetupRecursive(mock, expression, setupLast: (targetMock, oe, part) => { var originalExpression = (LambdaExpression)oe; @@ -583,7 +583,7 @@ internal static bool SetupReturns(Mock mock, LambdaExpression expression, object return true; } - internal static MethodCall SetupAdd(Mock mock, LambdaExpression expression, Condition condition) + internal static MethodCall SetupAdd(Mock mock, LambdaExpression expression, Condition? condition) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventAdd(expression, nameof(expression)); @@ -591,7 +591,7 @@ internal static MethodCall SetupAdd(Mock mock, LambdaExpression expression, Cond return Mock.Setup(mock, expression, condition); } - internal static MethodCall SetupRemove(Mock mock, LambdaExpression expression, Condition condition) + internal static MethodCall SetupRemove(Mock mock, LambdaExpression expression, Condition? condition) { Guard.NotNull(expression, nameof(expression)); Guard.IsEventRemove(expression, nameof(expression)); @@ -611,7 +611,7 @@ internal static SequenceSetup SetupSequence(Mock mock, LambdaExpression expressi }); } - internal static StubbedPropertySetup SetupProperty(Mock mock, LambdaExpression expression, object initialValue) + internal static StubbedPropertySetup SetupProperty(Mock mock, LambdaExpression expression, object? initialValue) { Guard.NotNull(expression, nameof(expression)); @@ -636,7 +636,7 @@ internal static StubbedPropertySetup SetupProperty(Mock mock, LambdaExpression e } static TSetup SetupRecursive(Mock mock, LambdaExpression expression, Func setupLast, bool allowNonOverridableLastProperty = false) - where TSetup : ISetup + where TSetup : ISetup? { Debug.Assert(mock != null); Debug.Assert(expression != null); @@ -647,7 +647,7 @@ static TSetup SetupRecursive(Mock mock, LambdaExpression expression, Fun } static TSetup SetupRecursive(Mock mock, LambdaExpression originalExpression, Stack parts, Func setupLast) - where TSetup : ISetup + where TSetup : ISetup? { var part = parts.Pop(); var (expr, method, arguments) = part; @@ -658,7 +658,7 @@ static TSetup SetupRecursive(Mock mock, LambdaExpression originalExpress } else { - Mock innerMock = mock.MutableSetups.FindLastInnerMock(setup => setup.Matches(part)); + Mock? innerMock = mock.MutableSetups.FindLastInnerMock(setup => setup.Matches(part)); if (innerMock == null) { var returnValue = mock.GetDefaultValue(method, out innerMock, useAlternateProvider: DefaultValueProvider.Mock); @@ -697,16 +697,18 @@ internal static void RaiseEvent(Mock mock, Action action, object[] argumen Mock.RaiseEvent(mock, expression, parts, arguments); } - internal static Task RaiseEventAsync(Mock mock, Action action, object[] arguments) + internal static Task RaiseEventAsync(Mock mock, Action action, object?[] arguments) { Guard.NotNull(action, nameof(action)); var expression = ExpressionReconstructor.Instance.ReconstructExpression(action, mock.ConstructorArguments); var parts = expression.Split(); + + // TODO: Will this code never return null? return (Task)Mock.RaiseEvent(mock, expression, parts, arguments); } - internal static object RaiseEvent(Mock mock, LambdaExpression expression, Stack parts, object[] arguments) + internal static object? RaiseEvent(Mock mock, LambdaExpression expression, Stack parts, object?[] arguments) { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; @@ -719,28 +721,22 @@ internal static object RaiseEvent(Mock mock, LambdaExpression expression, Stack< if (method.IsEventAddAccessor()) { var implementingMethod = method.GetImplementingMethod(mock.Object.GetType()); - @event = implementingMethod.DeclaringType.GetEvents(bindingFlags).SingleOrDefault(e => e.GetAddMethod(true) == implementingMethod); - if (@event == null) - { - throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - Resources.SetupNotEventAdd, - part.Expression)); - } + @event = implementingMethod.DeclaringType!.GetEvents(bindingFlags) + .SingleOrDefault(e => e.GetAddMethod(true) == implementingMethod) + ?? throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, + Resources.SetupNotEventAdd, + part.Expression)); + } else if (method.IsEventRemoveAccessor()) { var implementingMethod = method.GetImplementingMethod(mock.Object.GetType()); - @event = implementingMethod.DeclaringType.GetEvents(bindingFlags).SingleOrDefault(e => e.GetRemoveMethod(true) == implementingMethod); - if (@event == null) - { - throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - Resources.SetupNotEventRemove, - part.Expression)); - } + @event = implementingMethod.DeclaringType!.GetEvents(bindingFlags) + .SingleOrDefault(e => e.GetRemoveMethod(true) == implementingMethod) + ?? throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, + Resources.SetupNotEventRemove, + part.Expression)); + } else { @@ -820,7 +816,7 @@ internal bool ImplementsInterface(Type interfaceType) #region Default Values - internal abstract Dictionary ConfiguredDefaultValues { get; } + internal abstract Dictionary ConfiguredDefaultValues { get; } /// /// Defines the default return value for all mocked methods or properties with return type . @@ -835,13 +831,13 @@ public void SetReturnsDefault(TReturn value) this.ConfiguredDefaultValues[typeof(TReturn)] = value; } - internal object GetDefaultValue(MethodInfo method, out Mock candidateInnerMock, DefaultValueProvider useAlternateProvider = null) + internal object? GetDefaultValue(MethodInfo method, out Mock? candidateInnerMock, DefaultValueProvider? useAlternateProvider = null) { Debug.Assert(method != null); Debug.Assert(method.ReturnType != null); Debug.Assert(method.ReturnType != typeof(void)); - if (this.ConfiguredDefaultValues.TryGetValue(method.ReturnType, out object configuredDefaultValue)) + if (this.ConfiguredDefaultValues.TryGetValue(method.ReturnType, out object? configuredDefaultValue)) { candidateInnerMock = null; return configuredDefaultValue; diff --git a/src/Moq/MockDefaultValueProvider.cs b/src/Moq/MockDefaultValueProvider.cs index ce97416b1..2458e9758 100644 --- a/src/Moq/MockDefaultValueProvider.cs +++ b/src/Moq/MockDefaultValueProvider.cs @@ -19,7 +19,7 @@ internal MockDefaultValueProvider() internal override DefaultValue Kind => DefaultValue.Mock; - protected override object GetFallbackDefaultValue(Type type, Mock mock) + protected override object? GetFallbackDefaultValue(Type type, Mock mock) { Debug.Assert(type != null); Debug.Assert(type != typeof(void)); @@ -34,7 +34,7 @@ protected override object GetFallbackDefaultValue(Type type, Mock mock) { // Create a new mock to be placed to InnerMocks dictionary if it's missing there var mockType = typeof(Mock<>).MakeGenericType(type); - Mock newMock = (Mock)Activator.CreateInstance(mockType, mock.Behavior); + Mock newMock = (Mock)Activator.CreateInstance(mockType, mock.Behavior)!; newMock.DefaultValueProvider = mock.DefaultValueProvider; if (mock.MutableSetups.FindLast(s => s is StubbedPropertiesSetup) is StubbedPropertiesSetup sts) { diff --git a/src/Moq/MockException.cs b/src/Moq/MockException.cs index 538a9349f..ebd608bc3 100644 --- a/src/Moq/MockException.cs +++ b/src/Moq/MockException.cs @@ -56,7 +56,7 @@ internal static MockException IncorrectNumberOfCalls(MethodCall setup, Times tim internal static MockException NoMatchingCalls( Mock rootMock, LambdaExpression expression, - string failMessage, + string? failMessage, Times times, int callCount) { @@ -172,7 +172,7 @@ internal static MockException FromInnerMockOf(ISetup setup, MockException error) /// and whose reason(s) is the combination of the given ' reason(s). /// Used by when it finds one or more mocks with verification errors. /// - internal static MockException Combined(IEnumerable errors, string preamble) + internal static MockException Combined(IEnumerable errors, string? preamble) { Debug.Assert(errors != null); Debug.Assert(errors.Any()); @@ -248,7 +248,7 @@ protected MockException( System.Runtime.Serialization.StreamingContext context) : base(info, context) { - this.reasons = (MockExceptionReasons)info.GetValue(nameof(this.reasons), typeof(MockExceptionReasons)); + this.reasons = (MockExceptionReasons)info.GetValue(nameof(this.reasons), typeof(MockExceptionReasons))!; } /// diff --git a/src/Moq/Mock`1.cs b/src/Moq/Mock`1.cs index d9e697875..2279f986e 100644 --- a/src/Moq/Mock`1.cs +++ b/src/Moq/Mock`1.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Text; @@ -84,10 +85,10 @@ static Mock() serialNumberCounter = 0; } - T instance; + T? instance; List additionalInterfaces; - Dictionary configuredDefaultValues; - object[] constructorArguments; + Dictionary configuredDefaultValues; + object?[] constructorArguments; DefaultValueProvider defaultValueProvider; EventHandlerCollection eventHandlers; InvocationCollection invocations; @@ -110,6 +111,7 @@ internal Mock(bool skipInitialize) // The skipInitialize parameter is not used at all, and it's // just to differentiate this ctor that should do nothing // from the regular ones which initializes the proxy, etc. + // TODO: How should nullable references be handled here? } /// @@ -176,7 +178,7 @@ public Mock(MockBehavior behavior, params object?[]? args) this.additionalInterfaces = new List(); this.behavior = behavior; - this.configuredDefaultValues = new Dictionary(); + this.configuredDefaultValues = new Dictionary(); this.constructorArguments = args; this.defaultValueProvider = DefaultValueProvider.Empty; this.eventHandlers = new EventHandlerCollection(); @@ -248,9 +250,9 @@ public override bool CallBase } } - internal override object[] ConstructorArguments => this.constructorArguments; + internal override object?[] ConstructorArguments => this.constructorArguments; - internal override Dictionary ConfiguredDefaultValues => this.configuredDefaultValues; + internal override Dictionary ConfiguredDefaultValues => this.configuredDefaultValues; /// /// Gets or sets the instance that will be used @@ -295,6 +297,9 @@ public override string ToString() return this.Name; } +#if NET + [MemberNotNull(nameof(instance))] +#endif void InitializeInstance() { // Determine the set of interfaces that the proxy object should additionally implement. @@ -623,7 +628,7 @@ public Mock SetupProperty(Expression> property) /// Assert.Equal(6, v.Value); /// /// - public Mock SetupProperty(Expression> property, TProperty initialValue) + public Mock SetupProperty(Expression> property, TProperty? initialValue) { Mock.SetupProperty(this, property, initialValue); return this; @@ -680,6 +685,11 @@ public ISetupSequentialAction SetupSequence(Expression> expression) /// public ISetupConditionResult When(Func condition) { + if (condition == null) + { + throw new ArgumentNullException(nameof(condition)); + } + return new WhenPhrase(this, new Condition(condition)); } diff --git a/src/Moq/Moq.csproj b/src/Moq/Moq.csproj index b7bd529a0..e74667224 100644 --- a/src/Moq/Moq.csproj +++ b/src/Moq/Moq.csproj @@ -10,7 +10,9 @@ - $(DefineConstants);FEATURE_DEFAULT_INTERFACE_IMPLEMENTATIONS + $(DefineConstants);NULLABLE_REFERENCE_TYPES;FEATURE_DEFAULT_INTERFACE_IMPLEMENTATIONS + enable + nullable diff --git a/src/Moq/Obsolete/MockFactory.cs b/src/Moq/Obsolete/MockFactory.cs index eb48d3892..023aeb4d1 100644 --- a/src/Moq/Obsolete/MockFactory.cs +++ b/src/Moq/Obsolete/MockFactory.cs @@ -222,7 +222,7 @@ public Mock Create() /// factory.Verify(); /// /// - public Mock Create(params object[] args) + public Mock Create(params object[]? args) where T : class { // "fix" compiler picking this overload instead of @@ -314,7 +314,7 @@ public Mock Create(Expression> newExpression, MockBehavior behavio /// Type to mock. /// The behavior for the new mock. /// Optional arguments for the construction of the mock. - protected virtual Mock CreateMock(MockBehavior behavior, object[] args) + protected virtual Mock CreateMock(MockBehavior behavior, object[]? args) where T : class { var mock = new Mock(behavior, args); diff --git a/src/Moq/Pair.cs b/src/Moq/Pair.cs index 973a73f62..c8e1e4133 100644 --- a/src/Moq/Pair.cs +++ b/src/Moq/Pair.cs @@ -28,7 +28,7 @@ public bool Equals(Pair other) && object.Equals(this.Item2, other.Item2); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Pair other && this.Equals(other); } diff --git a/src/Moq/Protected/IProtectedAsMock.cs b/src/Moq/Protected/IProtectedAsMock.cs index 878faaf3b..8c1c9a060 100644 --- a/src/Moq/Protected/IProtectedAsMock.cs +++ b/src/Moq/Protected/IProtectedAsMock.cs @@ -89,7 +89,7 @@ public interface IProtectedAsMock : IFluentInterface /// Type of the property. Typically omitted as it can be inferred from the expression. /// Lambda expression that specifies the property. /// Initial value for the property. - Mock SetupProperty(Expression> expression, TProperty initialValue = default(TProperty)); + Mock SetupProperty(Expression> expression, TProperty? initialValue = default(TProperty)); /// /// Return a sequence of values, once per call. @@ -111,11 +111,11 @@ public interface IProtectedAsMock : IFluentInterface /// Lambda expression that specifies the method invocation. /// /// Number of times that the invocation is expected to have occurred. - /// If omitted, assumed to be . /// + /// If omitted, assumed to be . /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void Verify(Expression> expression, Times? times = null, string failMessage = null); + void Verify(Expression> expression, Times? times = null, string? failMessage = null); /// /// Verifies that a specific invocation matching the given expression was performed on the mock. @@ -129,7 +129,7 @@ public interface IProtectedAsMock : IFluentInterface /// /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void Verify(Expression> expression, Times? times = null, string failMessage = null); + void Verify(Expression> expression, Times? times = null, string? failMessage = null); /// /// Verifies that a property was set on the mock. @@ -143,7 +143,7 @@ public interface IProtectedAsMock : IFluentInterface /// /// The invocation was not called the number of times specified by . /// - void VerifySet(Action setterExpression, Times? times = null, string failMessage = null); + void VerifySet(Action setterExpression, Times? times = null, string? failMessage = null); /// /// Verifies that a property was read on the mock. @@ -156,6 +156,6 @@ public interface IProtectedAsMock : IFluentInterface /// /// Message to include in the thrown if verification fails. /// The specified invocation did not occur (or did not occur the specified number of times). - void VerifyGet(Expression> expression, Times? times = null, string failMessage = null); + void VerifyGet(Expression> expression, Times? times = null, string? failMessage = null); } } diff --git a/src/Moq/Protected/ItExpr.cs b/src/Moq/Protected/ItExpr.cs index 4e655bf42..e2e77633a 100644 --- a/src/Moq/Protected/ItExpr.cs +++ b/src/Moq/Protected/ItExpr.cs @@ -113,7 +113,7 @@ public static Expression IsAny() /// public static Expression Is(Expression> match) { - Expression> expr = () => It.Is((Expression>)null); + Expression> expr = () => It.Is((Expression>)null!); return Expression.Call(((MethodCallExpression)expr.Body).Method, match); } diff --git a/src/Moq/Protected/ProtectedAsMock.cs b/src/Moq/Protected/ProtectedAsMock.cs index c3d61024f..73b624a00 100644 --- a/src/Moq/Protected/ProtectedAsMock.cs +++ b/src/Moq/Protected/ProtectedAsMock.cs @@ -100,7 +100,7 @@ public ISetupGetter SetupGet(Expression(setup); } - public Mock SetupProperty(Expression> expression, TProperty initialValue = default(TProperty)) + public Mock SetupProperty(Expression> expression, TProperty? initialValue = default(TProperty)) { Guard.NotNull(expression, nameof(expression)); @@ -153,7 +153,7 @@ public ISetupSequentialAction SetupSequence(Expression> expressi return new SetupSequencePhrase(setup); } - public void Verify(Expression> expression, Times? times = null, string failMessage = null) + public void Verify(Expression> expression, Times? times = null, string? failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -170,7 +170,7 @@ public void Verify(Expression> expression, Times? times = null, Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); } - public void Verify(Expression> expression, Times? times = null, string failMessage = null) + public void Verify(Expression> expression, Times? times = null, string? failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -187,7 +187,7 @@ public void Verify(Expression> expression, Times Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); } - public void VerifySet(Action setterExpression, Times? times = null, string failMessage = null) + public void VerifySet(Action setterExpression, Times? times = null, string? failMessage = null) { Guard.NotNull(setterExpression, nameof(setterExpression)); @@ -195,7 +195,7 @@ public void VerifySet(Action setterExpression, Times? times = null, str Mock.VerifySet(mock, rewrittenExpression, times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage); } - public void VerifyGet(Expression> expression, Times? times = null, string failMessage = null) + public void VerifyGet(Expression> expression, Times? times = null, string? failMessage = null) { Guard.NotNull(expression, nameof(expression)); diff --git a/src/Moq/Protected/ProtectedMock.cs b/src/Moq/Protected/ProtectedMock.cs index d6c8e808f..2007312f6 100644 --- a/src/Moq/Protected/ProtectedMock.cs +++ b/src/Moq/Protected/ProtectedMock.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Linq.Expressions; @@ -51,7 +52,7 @@ public ISetup Setup(string methodName, Type[] genericTypeArguments, bool exac return this.InternalSetup(methodName, genericTypeArguments, exactParameterMatch, args); } - ISetup InternalSetup(string methodName, Type[] genericTypeArguments, bool exactParameterMatch, params object[] args) + ISetup InternalSetup(string methodName, Type[]? genericTypeArguments, bool exactParameterMatch, params object[] args) { Guard.NotNull(methodName, nameof(methodName)); @@ -80,7 +81,7 @@ public ISetup Setup(string methodName, Type[] genericTypeAr return this.InternalSetup(methodName, genericTypeArguments, exactParameterMatch, args); } - ISetup InternalSetup(string methodName, Type[] genericTypeArguments, + ISetup InternalSetup(string methodName, Type[]? genericTypeArguments, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodName, nameof(methodName)); @@ -147,7 +148,7 @@ public ISetupSequentialAction SetupSequence(string methodOrPropertyName, Type[] return this.InternalSetupSequence(methodOrPropertyName, genericTypeArguments, exactParameterMatch, args); } - ISetupSequentialAction InternalSetupSequence(string methodOrPropertyName, Type[] genericTypeArguments, bool exactParameterMatch, params object[] args) + ISetupSequentialAction InternalSetupSequence(string methodOrPropertyName, Type[]? genericTypeArguments, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodOrPropertyName, nameof(methodOrPropertyName)); @@ -175,7 +176,7 @@ public ISetupSequentialResult SetupSequence(string methodOrPro return this.InternalSetupSequence(methodOrPropertyName, genericTypeArguments, exactParameterMatch, args); } - ISetupSequentialResult InternalSetupSequence(string methodOrPropertyName, Type[] genericTypeArguments, bool exactParameterMatch, params object[] args) + ISetupSequentialResult InternalSetupSequence(string methodOrPropertyName, Type[]? genericTypeArguments, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodOrPropertyName, nameof(methodOrPropertyName)); @@ -223,7 +224,7 @@ public void Verify(string methodName, Type[] genericTypeArguments, Times times, this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); } - void InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + void InternalVerify(string methodName, Type[]? genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodName, nameof(methodName)); @@ -256,7 +257,7 @@ public void Verify(string methodName, Type[] genericTypeArguments, Time this.InternalVerify(methodName, genericTypeArguments, times, exactParameterMatch, args); } - void InternalVerify(string methodName, Type[] genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) + void InternalVerify(string methodName, Type[]? genericTypeArguments, Times times, bool exactParameterMatch, params object[] args) { Guard.NotNullOrEmpty(methodName, nameof(methodName)); @@ -314,7 +315,7 @@ static Expression> GetMemberAccess(PropertyInfo proper return Expression.Lambda>(Expression.MakeMemberAccess(param, property), param); } - static MethodInfo GetMethod(string methodName, Type[] genericTypeArguments, bool exact, params object[] args) + static MethodInfo? GetMethod(string methodName, Type[]? genericTypeArguments, bool exact, params object[] args) { var argTypes = ToArgTypes(args); var methods = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) @@ -343,7 +344,7 @@ static Expression> GetMethodCall(MethodInfo method, object[] args) } // TODO should support arguments for property indexers - static PropertyInfo GetProperty(string propertyName) + static PropertyInfo? GetProperty(string propertyName) { return typeof(T).GetProperty( propertyName, @@ -359,7 +360,11 @@ static Expression> GetSetterExpression(PropertyInfo property, Expressi param); } - static void ThrowIfMemberMissing(string memberName, MemberInfo member) +#if NULLABLE_REFERENCE_TYPES + static void ThrowIfMemberMissing(string memberName, [NotNull] MemberInfo? member) +#else + static void ThrowIfMemberMissing(string memberName, MemberInfo? member) +#endif { if (member == null) { @@ -371,7 +376,11 @@ static void ThrowIfMemberMissing(string memberName, MemberInfo member) } } - static void ThrowIfMethodMissing(string methodName, MethodInfo method, object[] args) +#if NULLABLE_REFERENCE_TYPES + static void ThrowIfMethodMissing(string methodName, [NotNull] MethodInfo? method, object[] args) +#else + static void ThrowIfMethodMissing(string methodName, MethodInfo? method, object[] args) +#endif { if (method == null) { @@ -443,14 +452,14 @@ static void ThrowIfVoidMethod(MethodInfo method) } } - static Type[] ToArgTypes(object[] args) + static Type?[] ToArgTypes(object[] args) { if (args == null) { throw new ArgumentException(Resources.UseItExprIsNullRatherThanNullArgumentValue); } - var types = new Type[args.Length]; + var types = new Type?[args.Length]; for (int index = 0; index < args.Length; index++) { if (args[index] == null) @@ -503,9 +512,9 @@ static bool IsItRefAny(Expression expression) return ItRefAnyField(expression) != null; } - static FieldInfo ItRefAnyField(Expression expr) + static FieldInfo? ItRefAnyField(Expression expr) { - FieldInfo itRefAnyField = null; + FieldInfo? itRefAnyField = null; if (expr.NodeType == ExpressionType.MemberAccess) { @@ -514,7 +523,7 @@ static FieldInfo ItRefAnyField(Expression expr) { if (field.Name == nameof(It.Ref.IsAny)) { - var fieldDeclaringType = field.DeclaringType; + var fieldDeclaringType = field.DeclaringType!; if (fieldDeclaringType.IsGenericType) { var fieldDeclaringTypeDefinition = fieldDeclaringType.GetGenericTypeDefinition(); diff --git a/src/Moq/ReturnsExtensions.cs b/src/Moq/ReturnsExtensions.cs index 5247edcb5..dd61fd754 100644 --- a/src/Moq/ReturnsExtensions.cs +++ b/src/Moq/ReturnsExtensions.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Moq.Language; @@ -48,11 +49,11 @@ public static IReturnsResult ReturnsAsync(this IReturnsType of the return value. /// Returns verb which represents the mocked type and the task of return type /// The function that will calculate the return value. - public static IReturnsResult ReturnsAsync(this IReturns> mock, Func valueFunction) where TMock : class + public static IReturnsResult ReturnsAsync(this IReturns> mock, Func? valueFunction) where TMock : class { if (IsNullResult(valueFunction, typeof(TResult))) { - return mock.ReturnsAsync(() => default); + return mock.ReturnsAsync(() => default!); } return mock.Returns(() => Task.FromResult(valueFunction())); @@ -69,7 +70,7 @@ public static IReturnsResult ReturnsAsync(this IReturns default); + return mock.ReturnsAsync(() => default!); } return mock.Returns(() => new ValueTask(valueFunction())); @@ -283,7 +284,11 @@ public static IReturnsResult ThrowsAsync(this IReturns null; + public virtual Condition? Condition => null; public Expectation Expectation => this.expectation; public LambdaExpression Expression => this.expectation.Expression; - Mock ISetup.InnerMock => this.InnerMocks.SingleOrDefault(); + Mock? ISetup.InnerMock => this.InnerMocks.SingleOrDefault(); public virtual IEnumerable InnerMocks => Enumerable.Empty(); @@ -47,7 +47,7 @@ protected Setup(Expression originalExpression, Mock mock, Expectation expectatio public Mock Mock => this.mock; - public Expression OriginalExpression => this.originalExpression; + public Expression? OriginalExpression => this.originalExpression; public bool IsMatched => (this.flags & Flags.Matched) != 0; @@ -204,7 +204,7 @@ void Verify(bool recursive, Func predicate) this.Verify(recursive, predicate, verifiedMocks); } - protected static Mock TryGetInnerMockFrom(object returnValue) + protected static Mock? TryGetInnerMockFrom(object? returnValue) { return (Awaitable.TryGetResultRecursive(returnValue) as IMocked)?.Mock; } diff --git a/src/Moq/SetupCollection.cs b/src/Moq/SetupCollection.cs index 7c210c9a6..c21907bfb 100644 --- a/src/Moq/SetupCollection.cs +++ b/src/Moq/SetupCollection.cs @@ -101,7 +101,7 @@ public List FindAll(Func predicate) return setups; } - public Setup FindLast(Func predicate) + public Setup? FindLast(Func predicate) { // Fast path (no `lock`) when there are no setups: if (this.setups.Count == 0) diff --git a/src/Moq/SetupWithOutParameterSupport.cs b/src/Moq/SetupWithOutParameterSupport.cs index d08ee3518..eabf6dd35 100644 --- a/src/Moq/SetupWithOutParameterSupport.cs +++ b/src/Moq/SetupWithOutParameterSupport.cs @@ -13,9 +13,9 @@ namespace Moq { abstract class SetupWithOutParameterSupport : MethodSetup { - readonly List> outValues; + readonly List>? outValues; - protected SetupWithOutParameterSupport(Expression originalExpression, Mock mock, MethodExpectation expectation) + protected SetupWithOutParameterSupport(Expression? originalExpression, Mock mock, MethodExpectation expectation) : base(originalExpression, mock, expectation) { Debug.Assert(expectation != null); @@ -34,9 +34,9 @@ public sealed override void SetOutParameters(Invocation invocation) } } - static List> GetOutValues(IReadOnlyList arguments, ParameterInfo[] parameters) + static List>? GetOutValues(IReadOnlyList arguments, ParameterInfo[] parameters) { - List> outValues = null; + List>? outValues = null; for (int i = 0, n = parameters.Length; i < n; ++i) { var parameter = parameters[i]; @@ -51,10 +51,10 @@ static List> GetOutValues(IReadOnlyList ar if (outValues == null) { - outValues = new List>(); + outValues = new List>(); } - outValues.Add(new KeyValuePair(i, constant.Value)); + outValues.Add(new KeyValuePair(i, constant.Value)); } } } diff --git a/src/Moq/StringBuilderExtensions.AppendExpression.cs b/src/Moq/StringBuilderExtensions.AppendExpression.cs index 5204b502b..518e52038 100644 --- a/src/Moq/StringBuilderExtensions.AppendExpression.cs +++ b/src/Moq/StringBuilderExtensions.AppendExpression.cs @@ -17,7 +17,7 @@ namespace Moq // These methods are intended to create more readable string representations for use in failure messages. partial class StringBuilderExtensions { - public static StringBuilder AppendExpression(this StringBuilder builder, Expression expression) + public static StringBuilder AppendExpression(this StringBuilder builder, Expression? expression) { if (expression == null) { @@ -273,7 +273,7 @@ static StringBuilder AppendExpression(this StringBuilder builder, MemberExpressi } else { - builder.AppendNameOf(expression.Member.DeclaringType); + builder.AppendNameOf(expression.Member.DeclaringType!); } return builder.Append('.') @@ -300,7 +300,7 @@ static StringBuilder AppendExpression(this StringBuilder builder, MethodCallExpr { Debug.Assert(method.IsStatic); - builder.AppendNameOf(method.DeclaringType); + builder.AppendNameOf(method.DeclaringType!); } if (method.IsGetAccessor()) @@ -380,7 +380,7 @@ static StringBuilder AppendExpression(this StringBuilder builder, LambdaExpressi static StringBuilder AppendExpression(this StringBuilder builder, NewExpression expression) { - Type type = (expression.Constructor == null) ? expression.Type : expression.Constructor.DeclaringType; + Type type = (expression.Constructor == null) ? expression.Type : expression.Constructor.DeclaringType!; return builder.Append("new ") .AppendNameOf(type) .AppendCommaSeparated("(", expression.Arguments, AppendExpression, ")"); @@ -395,7 +395,7 @@ static StringBuilder AppendExpression(this StringBuilder builder, NewArrayExpres case ExpressionType.NewArrayBounds: return builder.Append("new ") - .AppendNameOf(expression.Type.GetElementType()) + .AppendNameOf(expression.Type.GetElementType()!) .AppendCommaSeparated("[", expression.Expressions, AppendExpression, "]"); } diff --git a/src/Moq/StringBuilderExtensions.cs b/src/Moq/StringBuilderExtensions.cs index 127e665b1..939d0bd53 100644 --- a/src/Moq/StringBuilderExtensions.cs +++ b/src/Moq/StringBuilderExtensions.cs @@ -95,7 +95,7 @@ public static StringBuilder AppendParameterType(this StringBuilder stringBuilder _ => "ref ", }); - parameterType = parameterType.GetElementType(); + parameterType = parameterType.GetElementType()!; } if (parameterType.IsArray && parameter.IsDefined(typeof(ParamArrayAttribute), true)) @@ -106,7 +106,7 @@ public static StringBuilder AppendParameterType(this StringBuilder stringBuilder return stringBuilder.AppendFormattedName(parameterType); } - public static StringBuilder AppendValueOf(this StringBuilder stringBuilder, object obj) + public static StringBuilder AppendValueOf(this StringBuilder stringBuilder, object? obj) { if (obj == null) { @@ -128,12 +128,11 @@ public static StringBuilder AppendValueOf(this StringBuilder stringBuilder, obje { stringBuilder.AppendNameOf(obj.GetType()).Append('.').Append(obj); } - else if (obj.GetType().IsArray || (obj.GetType().IsConstructedGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(List<>))) + else if (obj is IReadOnlyList list) { stringBuilder.Append('['); const int maxCount = 10; - var enumerator = ((IEnumerable)obj).GetEnumerator(); - for (int i = 0; enumerator.MoveNext() && i < maxCount + 1; ++i) + for (var i = 0; i < list.Count; i++) { if (i > 0) { @@ -146,8 +145,9 @@ public static StringBuilder AppendValueOf(this StringBuilder stringBuilder, obje break; } - stringBuilder.AppendValueOf(enumerator.Current); + stringBuilder.AppendValueOf(list[i]); } + stringBuilder.Append(']'); } else diff --git a/src/Moq/StubbedPropertiesSetup.cs b/src/Moq/StubbedPropertiesSetup.cs index 7350b9a6b..15620cf12 100644 --- a/src/Moq/StubbedPropertiesSetup.cs +++ b/src/Moq/StubbedPropertiesSetup.cs @@ -12,13 +12,13 @@ namespace Moq { sealed class StubbedPropertiesSetup : Setup { - readonly ConcurrentDictionary values; + readonly ConcurrentDictionary values; readonly DefaultValueProvider defaultValueProvider; - public StubbedPropertiesSetup(Mock mock, DefaultValueProvider defaultValueProvider = null) + public StubbedPropertiesSetup(Mock mock, DefaultValueProvider? defaultValueProvider = null) : base(originalExpression: null, mock, new PropertyAccessorExpectation(mock)) { - this.values = new ConcurrentDictionary(); + this.values = new ConcurrentDictionary(); this.defaultValueProvider = defaultValueProvider ?? mock.DefaultValueProvider; this.MarkAsVerifiable(); @@ -79,7 +79,7 @@ public PropertyAccessorExpectation(Mock mock) Debug.Assert(mock != null); var mockType = mock.GetType(); - var setupAllPropertiesMethod = mockType.GetMethod(nameof(Mock.SetupAllProperties)); + var setupAllPropertiesMethod = mockType.GetMethod(nameof(Mock.SetupAllProperties))!; var mockedType = setupAllPropertiesMethod.ReturnType.GetGenericArguments()[0]; var mockGetMethod = Mock.GetMethod.MakeGenericMethod(mockedType); var mockParam = E.Parameter(mockedType, "m"); @@ -88,7 +88,7 @@ public PropertyAccessorExpectation(Mock mock) public override LambdaExpression Expression => this.expression; - public override bool Equals(Expectation other) + public override bool Equals(Expectation? other) { return other is PropertyAccessorExpectation pae && ExpressionComparer.Default.Equals(this.expression, pae.expression); } diff --git a/src/Moq/StubbedPropertySetup.cs b/src/Moq/StubbedPropertySetup.cs index eb1bb2283..0bb7ade60 100644 --- a/src/Moq/StubbedPropertySetup.cs +++ b/src/Moq/StubbedPropertySetup.cs @@ -10,9 +10,9 @@ namespace Moq { sealed class StubbedPropertySetup : Setup { - object value; + object? value; - public StubbedPropertySetup(Mock mock, LambdaExpression expression, MethodInfo getter, MethodInfo setter, object initialValue) + public StubbedPropertySetup(Mock mock, LambdaExpression expression, MethodInfo? getter, MethodInfo? setter, object? initialValue) : base(originalExpression: null, mock, new PropertyAccessorExpectation(expression, getter, setter)) { // NOTE: @@ -70,10 +70,10 @@ protected override void VerifySelf() sealed class PropertyAccessorExpectation : Expectation { readonly LambdaExpression expression; - readonly MethodInfo getter; - readonly MethodInfo setter; + readonly MethodInfo? getter; + readonly MethodInfo? setter; - public PropertyAccessorExpectation(LambdaExpression expression, MethodInfo getter, MethodInfo setter) + public PropertyAccessorExpectation(LambdaExpression expression, MethodInfo? getter, MethodInfo? setter) { Debug.Assert(expression != null); Debug.Assert(expression.IsProperty()); @@ -86,7 +86,7 @@ public PropertyAccessorExpectation(LambdaExpression expression, MethodInfo gette public override LambdaExpression Expression => this.expression; - public override bool Equals(Expectation obj) + public override bool Equals(Expectation? obj) { return obj is PropertyAccessorExpectation other && other.getter == this.getter @@ -101,7 +101,7 @@ public override int GetHashCode() public override bool IsMatch(Invocation invocation) { var methodName = invocation.Method.Name; - return methodName == this.getter.Name || methodName == this.setter.Name; + return methodName == this.getter?.Name || methodName == this.setter?.Name; } } } diff --git a/src/Moq/Times.cs b/src/Moq/Times.cs index e92ac06dd..1906d01ae 100644 --- a/src/Moq/Times.cs +++ b/src/Moq/Times.cs @@ -192,7 +192,7 @@ public bool Equals(Times other) /// if has the same value as this instance; /// otherwise, . /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Times other && this.Equals(other); } diff --git a/src/Moq/TypeMatcherAttribute.cs b/src/Moq/TypeMatcherAttribute.cs index 7e7db6402..96a0a6834 100644 --- a/src/Moq/TypeMatcherAttribute.cs +++ b/src/Moq/TypeMatcherAttribute.cs @@ -16,7 +16,7 @@ namespace Moq [AttributeUsage(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] public class TypeMatcherAttribute : Attribute { - readonly Type type; + readonly Type? type; /// /// Initializes a new instance of the class. @@ -39,14 +39,9 @@ public TypeMatcherAttribute() /// The of a type that implements . public TypeMatcherAttribute(Type type) { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - this.type = type; + this.type = type ?? throw new ArgumentNullException(nameof(type)); } - internal Type Type => this.type; + internal Type? Type => this.type; } }