Skip to content

Commit

Permalink
[GH-35] - rest of the Arg methods reports warnings when used in non-v…
Browse files Browse the repository at this point in the history
…irtual calls
  • Loading branch information
tpodolak committed Nov 24, 2019
1 parent 81963b4 commit 9a02e5a
Show file tree
Hide file tree
Showing 13 changed files with 583 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public class ArgumentMatcherDiagnosticsSource
public void NS5001_ArgumentMatcherUsedWithoutSpecifyingCall()
{
var substitute = Substitute.For<Foo>();

substitute.ObjectReturningMethodWithArguments(Arg.Any<int>(), Arg.Compat.Any<int>(), Arg.Is(1m));
substitute.ObjectReturningMethodWithArguments(Arg.Any<int>(), Arg.Compat.Any<int>(), Arg.Is(1m));
substitute.InternalObjectReturningMethodWithArguments(Arg.Is(1));
Expand All @@ -18,4 +17,4 @@ public void NS5001_ArgumentMatcherUsedWithoutSpecifyingCall()
_ = substitute[Arg.Compat.Any<int>()];
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,22 @@ private void AnalyzeArgLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, T
return;
}

var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(enclosingExpression).Symbol;
var canBeSetuped = symbol.CanBeSetuped();
var enclosingExpressionSymbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(enclosingExpression).Symbol;

if (canBeSetuped == false || symbol.MemberVisibleToProxyGenerator() == false)
if (enclosingExpressionSymbol == null)
{
return;
}

var canBeSetuped = enclosingExpressionSymbol.CanBeSetuped();

if (canBeSetuped == false || enclosingExpressionSymbol.MemberVisibleToProxyGenerator() == false)
{
var diagnostic = Diagnostic.Create(
DiagnosticDescriptorsProvider.ArgumentMatcherUsedWithoutSpecifyingCall,
argInvocationExpression.GetLocation());

TryReportDiagnostic(syntaxNodeContext, diagnostic, symbol);
TryReportDiagnostic(syntaxNodeContext, diagnostic, enclosingExpressionSymbol);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,6 @@ public static bool IsArgMatcherLikeMethod(this ISymbol symbol)
return IsMember(symbol, MetadataNames.ArgMatchersMethodNames) || IsMember(symbol, MetadataNames.ArgMatchersCompatMethodNames);
}

public static bool IsArgInvokerLikeMethod(this ISymbol symbol)
{
return IsMember(symbol, MetadataNames.ArgInvokersMethodNames) || IsMember(symbol, MetadataNames.ArgInvokersCompatMethodNames);
}

public static bool IsReceivedInOrderMethod(this ISymbol symbol)
{
return IsMember(symbol, MetadataNames.NSubstituteInOrderMethod, MetadataNames.NSubstituteReceivedFullTypeName);
}

public static bool IsSubstituteCreateLikeMethod(this ISymbol symbol)
{
return IsMember(symbol, MetadataNames.CreateSubstituteMethodNames);
Expand Down
23 changes: 6 additions & 17 deletions src/NSubstitute.Analyzers.Shared/MetadataNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ internal class MetadataNames
public const string NSubstituteArgFullTypeName = "NSubstitute.Arg";
public const string NSubstituteArgCompatFullTypeName = "NSubstitute.Arg.Compat";
public const string NSubstituteSubstituteExtensionsFullTypeName = "NSubstitute.SubstituteExtensions";
public const string NSubstituteReceivedFullTypeName = "NSubstitute.Received";
public const string NSubstituteReturnsExtensionsFullTypeName = "NSubstitute.ReturnsExtensions.ReturnsExtensions";
public const string NSubstituteExceptionExtensionsFullTypeName = "NSubstitute.ExceptionExtensions.ExceptionExtensions";
public const string NSubstituteCallInfoFullTypeName = "NSubstitute.Core.CallInfo";
Expand All @@ -27,7 +26,6 @@ internal class MetadataNames
public const string NSubstituteReceivedWithAnyArgsMethod = "ReceivedWithAnyArgs";
public const string NSubstituteDidNotReceiveMethod = "DidNotReceive";
public const string NSubstituteDidNotReceiveWithAnyArgsMethod = "DidNotReceiveWithAnyArgs";
public const string NSubstituteInOrderMethod = "InOrder";
public const string NSubstituteForMethod = "For";
public const string NSubstituteForPartsOfMethod = "ForPartsOf";
public const string SubstituteFactoryCreate = "Create";
Expand All @@ -39,7 +37,6 @@ internal class MetadataNames
public const string NSubstituteWhenCalledType = "WhenCalled";
public const string CallInfoArgAtMethod = "ArgAt";
public const string CallInfoArgMethod = "Arg";
public const string CallInfoArgsMethod = "Args";
public const string CallInfoArgTypesMethod = "ArgTypes";
public const string ArgIsMethodName = "Is";
public const string ArgAnyMethodName = "Any";
Expand Down Expand Up @@ -78,26 +75,18 @@ internal class MetadataNames
public static readonly IReadOnlyDictionary<string, string> ArgMatchersMethodNames = new Dictionary<string, string>
{
[ArgIsMethodName] = NSubstituteArgFullTypeName,
[ArgAnyMethodName] = NSubstituteArgFullTypeName
};

public static readonly IReadOnlyDictionary<string, string> ArgMatchersCompatMethodNames = new Dictionary<string, string>
{
[ArgIsMethodName] = NSubstituteArgCompatFullTypeName,
[ArgAnyMethodName] = NSubstituteArgCompatFullTypeName
};

public static readonly IReadOnlyDictionary<string, string> ArgInvokersMethodNames = new Dictionary<string, string>
{
[ArgInvokeMethodName] = NSubstituteArgFullTypeName,
[ArgAnyMethodName] = NSubstituteArgFullTypeName,
[ArgDoMethodName] = NSubstituteArgFullTypeName,
[ArgInvokeMethodName] = NSubstituteArgFullTypeName,
[ArgInvokeDelegateMethodName] = NSubstituteArgFullTypeName
};

public static readonly IReadOnlyDictionary<string, string> ArgInvokersCompatMethodNames = new Dictionary<string, string>
public static readonly IReadOnlyDictionary<string, string> ArgMatchersCompatMethodNames = new Dictionary<string, string>
{
[ArgInvokeMethodName] = NSubstituteArgCompatFullTypeName,
[ArgIsMethodName] = NSubstituteArgCompatFullTypeName,
[ArgAnyMethodName] = NSubstituteArgCompatFullTypeName,
[ArgDoMethodName] = NSubstituteArgCompatFullTypeName,
[ArgInvokeMethodName] = NSubstituteArgCompatFullTypeName,
[ArgInvokeDelegateMethodName] = NSubstituteArgCompatFullTypeName
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageReference Include="NSubstitute" Version="4.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\benchmarks\NSubstitute.Analyzers.Benchmarks\NSubstitute.Analyzers.Benchmarks.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
using NSubstitute.Analyzers.CSharp;
using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers;
using NSubstitute.Analyzers.Shared;
using NSubstitute.Analyzers.Shared.Settings;
using NSubstitute.Analyzers.Shared.TinyJson;
using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers;
using Xunit;

namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.ArgumentMatcherAnalyzerTests
{
public abstract class ArgumentMatcherDiagnosticVerifier : CSharpDiagnosticVerifier, IArgumentMatcherDiagnosticVerifier
{
internal AnalyzersSettings Settings { get; set; }

protected DiagnosticDescriptor ArgumentMatcherUsedWithoutSpecifyingCall { get; } = DiagnosticDescriptors<DiagnosticDescriptorsProvider>.ArgumentMatcherUsedWithoutSpecifyingCall;

[Theory]
Expand Down Expand Up @@ -94,6 +98,10 @@ public abstract class ArgumentMatcherDiagnosticVerifier : CSharpDiagnosticVerifi
[MemberData(nameof(CorrectlyUsedArgTestCases))]
public abstract Task ReportsNoDiagnostics_WhenUsedInProtectedInternalVirtualMember(string arg);

[Theory]
[MemberData(nameof(CorrectlyUsedArgTestCasesWithoutCasts))]
public abstract Task ReportsNoDiagnosticsForSuppressedMember_WhenSuppressingNonVirtualMethod(string arg);

protected override DiagnosticAnalyzer GetDiagnosticAnalyzer()
{
return new ArgumentMatcherAnalyzer();
Expand All @@ -104,9 +112,23 @@ public static IEnumerable<object[]> MisusedArgTestCases
get
{
yield return new object[] { "[|Arg.Any<int>()|]" };
yield return new object[] { "(int)[|Arg.Any<int>()|]" };
yield return new object[] { "[|Arg.Any<int>()|] as int?" };
yield return new object[] { "[|Arg.Compat.Any<int>()|]" };
yield return new object[] { "(int)[|Arg.Compat.Any<int>()|]" };
yield return new object[] { "[|Arg.Compat.Any<int>()|] as int?" };
yield return new object[] { "[|Arg.Is(1)|]" };
yield return new object[] { "(int)[|Arg.Is(1)|]" };
yield return new object[] { "[|Arg.Is(1)|] as int?" };
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.Invoke()|]" };
yield return new object[] { "[|Arg.Compat.Invoke()|]" };
yield return new object[] { "[|Arg.InvokeDelegate<int>()|]" };
yield return new object[] { "[|Arg.Compat.InvokeDelegate<int>()|]" };
}
}

Expand All @@ -126,7 +148,39 @@ public static IEnumerable<object[]> CorrectlyUsedArgTestCases
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.Invoke()" };
yield return new object[] { "Arg.Compat.Invoke()" };
yield return new object[] { "Arg.InvokeDelegate<int>()" };
yield return new object[] { "(int)Arg.InvokeDelegate<int>()" };
yield return new object[] { "Arg.InvokeDelegate<int>() as int?" };
yield return new object[] { "Arg.Compat.InvokeDelegate<int>()" };
yield return new object[] { "(int)Arg.Compat.InvokeDelegate<int>()" };
yield return new object[] { "Arg.Compat.InvokeDelegate<int>() as int?" };
}
}

public static IEnumerable<object[]> CorrectlyUsedArgTestCasesWithoutCasts
{
get
{
yield return new object[] { "Arg.Any<int>()" };
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.Invoke()" };
yield return new object[] { "Arg.Compat.Invoke()" };
yield return new object[] { "Arg.InvokeDelegate<int>()" };
yield return new object[] { "Arg.Compat.InvokeDelegate<int>()" };
}
}

protected override string GetSettings()
{
return Settings != null ? Json.Encode(Settings) : null;
}
}
}
Loading

0 comments on commit 9a02e5a

Please sign in to comment.