Skip to content

Commit

Permalink
GH-212 - disable CallInfo analysis for Arg.AnyType matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
tpodolak committed Dec 25, 2023
1 parent 8e35c28 commit c890b1b
Show file tree
Hide file tree
Showing 16 changed files with 65 additions and 15 deletions.
Binary file modified libs/nsubstitute-latest/NSubstitute.dll
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ private void AnalyzeArgAtInvocations(OperationAnalysisContext operationAnalysisC
continue;
}

if (IsAssignableTo(
var substituteParameterTypeSymbol = substituteCallParameters[position.Value].GetTypeSymbol();
if (!substituteParameterTypeSymbol.IsArgAnyType(operationAnalysisContext.Compilation) && IsAssignableTo(
operationAnalysisContext.Compilation,
substituteCallParameters[position.Value].GetTypeSymbol(),
substituteParameterTypeSymbol,
argAtInvocation.TargetMethod.TypeArguments.First()) == false)
{
var diagnostic = Diagnostic.Create(
Expand Down Expand Up @@ -213,7 +214,9 @@ private bool AnalyzeCast(OperationAnalysisContext operationAnalysisContext, IRea
}

var type = conversionOperation.Type;
if (type != null && CanCast(operationAnalysisContext.Compilation, substituteCallParameters[position.Value].GetTypeSymbol(), type) == false)
var substituteParameterTypeSymbol = substituteCallParameters[position.Value].GetTypeSymbol();
if (type != null && !substituteParameterTypeSymbol.IsArgAnyType(operationAnalysisContext.Compilation) &&
CanCast(operationAnalysisContext.Compilation, substituteParameterTypeSymbol, type) == false)
{
var diagnostic = Diagnostic.Create(
DiagnosticDescriptorsProvider.CallInfoCouldNotConvertParameterAtPosition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ typeSymbol is INamedTypeSymbol namedTypeSymbol &&
return isCalledViaDelegate;
}

public static bool IsArgAnyType(this ITypeSymbol? typeSymbol, Compilation compilation)
{
return typeSymbol != null
&& typeSymbol.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.OrdinalIgnoreCase) == true
&& typeSymbol.ToString().Equals(MetadataNames.NSubstituteArgAnyTypeFullTypeName, StringComparison.OrdinalIgnoreCase);
}

public static bool IsCallInfoSymbol(this ITypeSymbol symbol)
{
return IsCallInfoSymbolInternal(symbol) || IsCallInfoSymbolInternal(symbol.BaseType);
Expand Down
1 change: 1 addition & 0 deletions src/NSubstitute.Analyzers.Shared/MetadataNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal class MetadataNames
public const string NSubstituteReturnsExtensionsFullTypeName = "NSubstitute.ReturnsExtensions.ReturnsExtensions";
public const string NSubstituteExceptionExtensionsFullTypeName = "NSubstitute.ExceptionExtensions.ExceptionExtensions";
public const string NSubstituteCallInfoFullTypeName = "NSubstitute.Core.CallInfo";
public const string NSubstituteArgAnyTypeFullTypeName = "NSubstitute.Arg.AnyType";
public const string NSubstituteConfiguredCallFullTypeName = "NSubstitute.Core.ConfiguredCall";
public const string NSubstituteSubstituteFullTypeName = "NSubstitute.Substitute";
public const string NSubstituteFactoryFullTypeName = "NSubstitute.Core.ISubstituteFactory";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ public abstract class CallInfoDiagnosticVerifier : CSharpDiagnosticVerifier, ICa
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = callInfo.Args()[1] as BarBase;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = callInfo.Args()[1] as object;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "var x = (int)callInfo.Args()[0];")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = (string)callInfo.Args()[1];")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = callInfo.Args()[1] as string;")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "var x = (string)callInfo[1];")]
public abstract Task ReportsNoDiagnostic_WhenManuallyCasting_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down Expand Up @@ -183,6 +186,7 @@ public abstract class CallInfoDiagnosticVerifier : CSharpDiagnosticVerifier, ICa
[InlineData("substitute[Arg.Any<decimal>(), Arg.Any<Bar>()]", "callInfo.ArgAt<object>(1);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "callInfo.ArgAt<int>(0);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Bar>()]", "callInfo.ArgAt<object>(0);")]
[InlineData("substitute[Arg.Any<int>(), Arg.Any<Arg.AnyType>()]", "callInfo.ArgAt<string>(1);")]
public abstract Task ReportsNoDiagnostic_WhenCasting_WithArgAt_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ public interface Foo
{{
int Bar(int x, Bar y);
int Bar(int x, object y);
int this[int x, Bar y] {{ get; }}
int this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,11 @@ public interface Foo
{{
Task<int> Bar(int x, Bar y);
Task<int> Bar(int x, object y);
Task<int> this[int x, Bar y] {{ get; }}
Task<int> this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,11 @@ public interface Foo
{{
Task<int> Bar(int x, Bar y);
Task<int> Bar(int x, object y);
Task<int> this[int x, Bar y] {{ get; }}
Task<int> this[int x, object y] {{ get; }}
}}
public class BarBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ public static IEnumerable<object[]> MisusedArgTestCases
yield return new object[] { "[|Arg.Compat.Is(1)|]" };
yield return new object[] { "(int)[|Arg.Compat.Is(1)|]" };
yield return new object[] { "[|Arg.Compat.Is(1)|] as int?" };
yield return new object[] { "[|Arg.Do<int>(__ => {})|]" };
yield return new object[] { "[|Arg.Compat.Do<int>(__ => {})|]" };
yield return new object[] { "[|Arg.Do<int>((int __) => {})|]" };
yield return new object[] { "[|Arg.Compat.Do<int>((int __) => {})|]" };
yield return new object[] { "[|Arg.Invoke()|]" };
yield return new object[] { "[|Arg.Compat.Invoke()|]" };
yield return new object[] { "[|Arg.InvokeDelegate<int>()|]" };
Expand Down Expand Up @@ -183,8 +183,8 @@ public static IEnumerable<object[]> CorrectlyUsedArgTestCases
yield return new object[] { "Arg.Compat.Is(1) as int?" };
yield return new object[] { "Arg.Compat.Is((int __) => __ > 0) " };
yield return new object[] { "true ? Arg.Compat.Is((int __) => __ > 0) : 0" };
yield return new object[] { "Arg.Do<int>(__ => {})" };
yield return new object[] { "Arg.Compat.Do<int>(__ => {})" };
yield return new object[] { "Arg.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Compat.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Invoke()" };
yield return new object[] { "Arg.Compat.Invoke()" };
yield return new object[] { "Arg.InvokeDelegate<int>()" };
Expand All @@ -207,8 +207,8 @@ public static IEnumerable<object[]> CorrectlyUsedArgTestCasesWithoutCasts
yield return new object[] { "Arg.Compat.Any<int>()" };
yield return new object[] { "Arg.Is(1)" };
yield return new object[] { "Arg.Compat.Is(1)" };
yield return new object[] { "Arg.Do<int>(__ => {})" };
yield return new object[] { "Arg.Compat.Do<int>(__ => {})" };
yield return new object[] { "Arg.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Compat.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Invoke()" };
yield return new object[] { "Arg.Compat.Invoke()" };
yield return new object[] { "Arg.InvokeDelegate<int>()" };
Expand All @@ -220,8 +220,8 @@ public static IEnumerable<object[]> AssignableArgMatchers
{
get
{
yield return new object[] { "Arg.Do<int>(__ => {})" };
yield return new object[] { "Arg.Compat.Do<int>(__ => {})" };
yield return new object[] { "Arg.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Compat.Do<int>((int __) => {})" };
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public static IEnumerable<object[]> MisusedArgTestCases
yield return new object[] { "[|Arg.Compat.Is(1)|]" };
yield return new object[] { "(int)[|Arg.Compat.Is(1)|]" };
yield return new object[] { "[|Arg.Compat.Is(1)|] as int?" };
yield return new object[] { "[|Arg.Do<int>(__ => {})|]" };
yield return new object[] { "[|Arg.Compat.Do<int>(__ => {})|]" };
yield return new object[] { "[|Arg.Do<int>((int __) => {})|]" };
yield return new object[] { "[|Arg.Compat.Do<int>((int __) => {})|]" };
yield return new object[] { "[|Arg.Invoke(1)|]" };
yield return new object[] { "[|Arg.Compat.Invoke(1)|]" };
yield return new object[] { "[|Arg.InvokeDelegate<Action<int>>()|]" };
Expand Down Expand Up @@ -90,8 +90,8 @@ public static IEnumerable<object[]> CorrectlyUsedArgTestCases
yield return new object[] { "Arg.Compat.Is(1) as int?" };
yield return new object[] { "Arg.Compat.Is((int __) => __ > 0) " };
yield return new object[] { "true ? Arg.Compat.Is((int __) => __ > 0) : 0" };
yield return new object[] { "Arg.Do<int>(__ => {})" };
yield return new object[] { "Arg.Compat.Do<int>(__ => {})" };
yield return new object[] { "Arg.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Compat.Do<int>((int __) => {})" };
yield return new object[] { "Arg.Invoke(1)" };
yield return new object[] { "Arg.Compat.Invoke(1)" };
yield return new object[] { "Arg.InvokeDelegate<Action<int>>()" };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ public abstract class CallInfoDiagnosticVerifier : VisualBasicDiagnosticVerifier
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Bar)())", "Dim x = DirectCast(callInfo.Args()(1), Object)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Bar)())", "Dim x = CType(callInfo.Args()(0), Integer)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Bar)())", "Dim x = DirectCast(callInfo.Args()(0), Integer)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Arg.AnyType)())", "Dim x = DirectCast(callInfo.Args()(1), String)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Arg.AnyType)())", "Dim x = CType(callInfo.Args()(1), String)")]
public abstract Task ReportsNoDiagnostic_WhenManuallyCasting_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down Expand Up @@ -219,6 +221,7 @@ public abstract class CallInfoDiagnosticVerifier : VisualBasicDiagnosticVerifier
[InlineData("substitute(Arg.Any(Of Decimal)(), Arg.Any(Of Bar)())", "callInfo.ArgAt(Of Object)(1)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Bar)())", "callInfo.ArgAt(Of Integer)(0)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Bar)())", "callInfo.ArgAt(Of Object)(0)")]
[InlineData("substitute(Arg.Any(Of Integer)(), Arg.Any(Of Arg.AnyType)())", "callInfo.ArgAt(Of String)(1)")]
public abstract Task ReportsNoDiagnostic_WhenCasting_WithArgAt_ToSupportedType(string method, string call, string argAccess);

[CombinatoryTheory]
Expand Down

0 comments on commit c890b1b

Please sign in to comment.