diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs index e18c3f06..89eb53eb 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -19,38 +19,6 @@ public CallInfoAnalyzer() protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - protected override SyntaxNode GetSubstituteCall(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) - { - if (methodSymbol.IsExtensionMethod) - { - switch (methodSymbol.MethodKind) - { - case MethodKind.ReducedExtension: - return invocationExpressionSyntax.Expression.DescendantNodes().First(); - case MethodKind.Ordinary: - return invocationExpressionSyntax.ArgumentList.Arguments.First().Expression; - default: - return null; - } - } - - var parentInvocation = invocationExpressionSyntax.GetParentInvocationExpression(); - - if (parentInvocation == null) - { - return null; - } - - var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(parentInvocation); - - if (symbol.Symbol is IMethodSymbol mSymbol && mSymbol.ReducedFrom == null) - { - return parentInvocation.ArgumentList.Arguments.First().Expression; - } - - return parentInvocation.Expression.DescendantNodes().First(); - } - protected override IEnumerable GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) { return invocationExpressionSyntax.ArgumentList.Arguments.Select(arg => arg.Expression); @@ -61,6 +29,11 @@ protected override AbstractCallInfoFinder GetSubstitutionNodeFinder() + { + return new SubstitutionNodeFinder(); + } + protected override SyntaxNode GetCastTypeExpression(ElementAccessExpressionSyntax indexerExpressionSyntax) { switch (indexerExpressionSyntax.Parent) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs deleted file mode 100644 index 7e965e1b..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; -using NSubstitute.Analyzers.CSharp.Extensions; -using NSubstitute.Analyzers.Shared.Extensions; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers -{ - [DiagnosticAnalyzer(LanguageNames.CSharp)] - internal class CallInfoDoAnalyzer : CallInfoAnalyzer - { - private readonly Lazy _whenSubstituteCallFinderProxy = new Lazy(() => new WhenSubstituteCallFinder()); - - private WhenSubstituteCallFinder WhenSubstituteCallFinder => _whenSubstituteCallFinderProxy.Value; - - protected override bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax syntax, IMethodSymbol methodSymbol) - { - if (methodSymbol.Name != "Do") - { - return false; - } - - var allArguments = GetArgumentExpressions(syntax); - return allArguments.Any(arg => syntaxNodeContext.SemanticModel.GetTypeInfo(arg).IsCallInfoDelegate(syntaxNodeContext.SemanticModel)); - } - - protected override SyntaxNode GetSubstituteCall(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) - { - var parentInvocationExpression = invocationExpressionSyntax.GetParentInvocationExpression(); - - if (parentInvocationExpression == null) - { - return null; - } - - return WhenSubstituteCallFinder.Find(syntaxNodeContext, parentInvocationExpression).FirstOrDefault(); - } - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs index 44f4746f..bb4daf67 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs @@ -19,13 +19,9 @@ public NonSubstitutableMemberWhenAnalyzer() protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - private readonly Lazy _whenSubstituteCallFinderProxy = new Lazy(() => new WhenSubstituteCallFinder()); - - private WhenSubstituteCallFinder WhenSubstituteCallFinder => _whenSubstituteCallFinderProxy.Value; - - protected override IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) + protected override AbstractSubstitutionNodeFinder GetSubstitutionNodeFinder() { - return WhenSubstituteCallFinder.Find(syntaxNodeAnalysisContext, invocationExpressionSyntax, methodSymbol); + return new SubstitutionNodeFinder(); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs new file mode 100644 index 00000000..3d40d6c1 --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.Extensions; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers +{ + /// + /// Finds nodes which are considered to be a part of substitution call. For instance substitute.Bar().Returns(1) will return substitute.Bar() + /// + internal class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder + { + public override IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, IMethodSymbol whenInvocationSymbol = null) + { + if (whenInvocationExpression == null) + { + return Enumerable.Empty(); + } + + whenInvocationSymbol = whenInvocationSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(whenInvocationExpression).Symbol as IMethodSymbol; + + if (whenInvocationSymbol == null) + { + return Enumerable.Empty(); + } + + var argumentExpression = whenInvocationSymbol.MethodKind == MethodKind.ReducedExtension + ? whenInvocationExpression.ArgumentList.Arguments.First().Expression + : whenInvocationExpression.ArgumentList.Arguments.Skip(1).First().Expression; + + return FindForWhenExpression(syntaxNodeContext, argumentExpression); + } + + public override SyntaxNode FindForAndDoesExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax invocationExpression, IMethodSymbol invocationExpressionSymbol) + { + var parentInvocationExpression = invocationExpression?.GetParentInvocationExpression(); + if (parentInvocationExpression == null) + { + return null; + } + + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(parentInvocationExpression); + + return symbol.Symbol is IMethodSymbol methodSymbol && methodSymbol.ReducedFrom == null + ? parentInvocationExpression.ArgumentList.Arguments.First().Expression + : parentInvocationExpression.Expression.DescendantNodes().First(); + } + + protected override InvocationExpressionSyntax GetParentInvocationExpression(InvocationExpressionSyntax invocationExpressionSyntax) + { + return invocationExpressionSyntax.GetParentInvocationExpression(); + } + + protected override SyntaxNode FindForStandardSubstitution(InvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol invocationExpressionSymbol) + { + switch (invocationExpressionSymbol.MethodKind) + { + case MethodKind.ReducedExtension: + return invocationExpressionSyntax.Expression.DescendantNodes().First(); + case MethodKind.Ordinary: + return invocationExpressionSyntax.ArgumentList.Arguments.First().Expression; + default: + return null; + } + } + + private IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) + { + SyntaxNode body = null; + switch (argumentSyntax) + { + case SimpleLambdaExpressionSyntax simpleLambdaExpressionSyntax: + body = simpleLambdaExpressionSyntax.Body; + break; + case AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax: + body = anonymousFunctionExpressionSyntax.Body; + break; + case LocalFunctionStatementSyntax localFunctionStatementSyntax: + body = (SyntaxNode)localFunctionStatementSyntax.Body ?? localFunctionStatementSyntax.ExpressionBody; + break; + case MethodDeclarationSyntax methodDeclarationSyntax: + body = (SyntaxNode)methodDeclarationSyntax.Body ?? methodDeclarationSyntax.ExpressionBody; + break; + case IdentifierNameSyntax identifierNameSyntax: + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(identifierNameSyntax); + if (symbol.Symbol != null && symbol.Symbol.Locations.Any()) + { + var location = symbol.Symbol.Locations.First(); + var syntaxNode = location.SourceTree.GetRoot().FindNode(location.SourceSpan); + + foreach (var expressionForAnalysis in FindForWhenExpression(syntaxNodeContext, syntaxNode)) + { + yield return expressionForAnalysis; + } + } + + break; + } + + if (body == null) + { + yield break; + } + + foreach (var invocationExpressionSyntax in body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.SimpleMemberAccessExpression) || + node.IsKind(SyntaxKind.ElementAccessExpression))) + { + yield return invocationExpressionSyntax; + } + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs deleted file mode 100644 index 99b87921..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers -{ - /// - /// Finds calls considered to be substitute calls in expressions - /// - internal class WhenSubstituteCallFinder - { - public IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, ISymbol whenInvocationSymbol = null) - { - if ((whenInvocationSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(whenInvocationExpression).Symbol) is IMethodSymbol parentInvocationSymbol) - { - var argumentExpression = parentInvocationSymbol.MethodKind == MethodKind.ReducedExtension - ? whenInvocationExpression.ArgumentList.Arguments.First().Expression - : whenInvocationExpression.ArgumentList.Arguments.Skip(1).First().Expression; - - return Find(syntaxNodeContext, argumentExpression); - } - - return null; - } - - private IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) - { - SyntaxNode body = null; - switch (argumentSyntax) - { - case SimpleLambdaExpressionSyntax simpleLambdaExpressionSyntax: - body = simpleLambdaExpressionSyntax.Body; - break; - case AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax: - body = anonymousFunctionExpressionSyntax.Body; - break; - case LocalFunctionStatementSyntax localFunctionStatementSyntax: - body = (SyntaxNode)localFunctionStatementSyntax.Body ?? localFunctionStatementSyntax.ExpressionBody; - break; - case MethodDeclarationSyntax methodDeclarationSyntax: - body = (SyntaxNode)methodDeclarationSyntax.Body ?? methodDeclarationSyntax.ExpressionBody; - break; - case IdentifierNameSyntax identifierNameSyntax: - var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(identifierNameSyntax); - if (symbol.Symbol != null && symbol.Symbol.Locations.Any()) - { - var location = symbol.Symbol.Locations.First(); - var syntaxNode = location.SourceTree.GetRoot().FindNode(location.SourceSpan); - - foreach (var expressionForAnalysis in Find(syntaxNodeContext, syntaxNode)) - { - yield return expressionForAnalysis; - } - } - - break; - } - - if (body == null) - { - yield break; - } - - foreach (var invocationExpressionSyntax in body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.SimpleMemberAccessExpression) || - node.IsKind(SyntaxKind.ElementAccessExpression))) - { - yield return invocationExpressionSyntax; - } - } - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index ef0455bb..b6c5a1b9 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -16,12 +16,17 @@ internal abstract class AbstractCallInfoAnalyzer> _callInfoFinderProxy; + private readonly Lazy> _substitutionNodeFinderProxy; + private AbstractCallInfoFinder CallInfoFinder => _callInfoFinderProxy.Value; + private AbstractSubstitutionNodeFinder SubstitutionNodeFinder => _substitutionNodeFinderProxy.Value; + protected AbstractCallInfoAnalyzer(IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) : base(diagnosticDescriptorsProvider) { _callInfoFinderProxy = new Lazy>(GetCallInfoFinder); + _substitutionNodeFinderProxy = new Lazy>(GetSubstitutionNodeFinder); } private static readonly ImmutableDictionary MethodNames = new Dictionary() @@ -30,7 +35,8 @@ protected AbstractCallInfoAnalyzer(IDiagnosticDescriptorsProvider diagnosticDesc [MetadataNames.NSubstituteReturnsForAnyArgsMethod] = MetadataNames.NSubstituteSubstituteExtensionsFullTypeName, [MetadataNames.NSubstituteThrowsMethod] = MetadataNames.NSubstituteExceptionExtensionsFullTypeName, [MetadataNames.NSubstituteThrowsForAnyArgsMethod] = MetadataNames.NSubstituteExceptionExtensionsFullTypeName, - [MetadataNames.NSubstituteAndDoesMethod] = MetadataNames.NSubstituteConfiguredCallFullTypeName + [MetadataNames.NSubstituteAndDoesMethod] = MetadataNames.NSubstituteConfiguredCallFullTypeName, + [MetadataNames.NSubstituteDoMethod] = MetadataNames.NSubstituteWhenCalledType }.ToImmutableDictionary(); public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( @@ -48,12 +54,12 @@ public override void Initialize(AnalysisContext context) protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected abstract SyntaxNode GetSubstituteCall(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, TInvocationExpressionSyntax invocationExpressionSyntax); - protected abstract IEnumerable GetArgumentExpressions(TInvocationExpressionSyntax invocationExpressionSyntax); protected abstract AbstractCallInfoFinder GetCallInfoFinder(); + protected abstract AbstractSubstitutionNodeFinder GetSubstitutionNodeFinder(); + protected abstract SyntaxNode GetCastTypeExpression(TIndexerExpressionSyntax indexerExpressionSyntax); protected abstract SyntaxNode GetAssignmentExpression(TIndexerExpressionSyntax indexerExpressionSyntax); @@ -68,13 +74,25 @@ public override void Initialize(AnalysisContext context) protected abstract bool IsAssignableTo(Compilation compilation, ITypeSymbol fromSymbol, ITypeSymbol toSymbol); - protected virtual bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, TInvocationExpressionSyntax syntax, IMethodSymbol methodSymbol) + private bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, TInvocationExpressionSyntax syntax, IMethodSymbol methodSymbol) { if (MethodNames.TryGetValue(methodSymbol.Name, out var typeName) == false) { return false; } + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntax); + + var supportsCallInfo = + symbol.Symbol?.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.OrdinalIgnoreCase) == true && + (symbol.Symbol?.ContainingType?.ToString().Equals(typeName, StringComparison.OrdinalIgnoreCase) == true || + (symbol.Symbol.ContainingType?.ConstructedFrom.Name)?.Equals(typeName, StringComparison.OrdinalIgnoreCase) == true); + + if (supportsCallInfo == false) + { + return false; + } + var allArguments = GetArgumentExpressions(syntax); IEnumerable argumentsForAnalysis; if (methodSymbol.MethodKind == MethodKind.ReducedExtension) @@ -84,13 +102,7 @@ protected virtual bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeCont else argumentsForAnalysis = allArguments; - var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntax); - - var supportsCallInfo = - symbol.Symbol?.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.OrdinalIgnoreCase) == true && - symbol.Symbol?.ContainingType?.ToString().Equals(typeName, StringComparison.OrdinalIgnoreCase) == true; - - return supportsCallInfo && argumentsForAnalysis.Any(arg => syntaxNodeContext.SemanticModel.GetTypeInfo(arg).IsCallInfoDelegate(syntaxNodeContext.SemanticModel)); + return argumentsForAnalysis.Any(arg => syntaxNodeContext.SemanticModel.GetTypeInfo(arg).IsCallInfoDelegate(syntaxNodeContext.SemanticModel)); } private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) @@ -291,7 +303,7 @@ private bool AnalyzeAssignment(SyntaxNodeAnalysisContext syntaxNodeContext, ILis private IList GetSubstituteCallParameters(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, TInvocationExpressionSyntax invocationExpression) { - var parentMethodCallSyntax = GetSubstituteCall(syntaxNodeContext, methodSymbol, invocationExpression); + var parentMethodCallSyntax = SubstitutionNodeFinder.Find(syntaxNodeContext, invocationExpression, methodSymbol).FirstOrDefault(); if (parentMethodCallSyntax == null) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs index 696f3bf3..5cc197d8 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs @@ -22,9 +22,14 @@ internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer> _substitutionNodeFinderProxy; + + private AbstractSubstitutionNodeFinder SubstitutionNodeFinderProxy => _substitutionNodeFinderProxy.Value; + protected AbstractNonSubstitutableMemberWhenAnalyzer(IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) : base(diagnosticDescriptorsProvider) { + _substitutionNodeFinderProxy = new Lazy>(GetSubstitutionNodeFinder); } public override void Initialize(AnalysisContext context) @@ -32,7 +37,7 @@ public override void Initialize(AnalysisContext context) context.RegisterSyntaxNodeAction(AnalyzeInvocation, InvocationExpressionKind); } - protected abstract IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, TInvocationExpressionSyntax invocationExpressionSyntax); + protected abstract AbstractSubstitutionNodeFinder GetSubstitutionNodeFinder(); private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) { @@ -55,7 +60,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - var expressionsForAnalysys = GetExpressionsForAnalysys(syntaxNodeContext, methodSymbol, invocationExpression); + var expressionsForAnalysys = SubstitutionNodeFinderProxy.FindForWhenExpression(syntaxNodeContext, invocationExpression, methodSymbol); var typeSymbol = methodSymbol.TypeArguments.FirstOrDefault() ?? methodSymbol.ReceiverType; foreach (var analysedSyntax in expressionsForAnalysys) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs new file mode 100644 index 00000000..e5d88dc0 --- /dev/null +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers +{ + internal abstract class AbstractSubstitutionNodeFinder + where TInvocationExpressionSyntax : SyntaxNode + { + public IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, TInvocationExpressionSyntax invocationExpression, IMethodSymbol invocationExpressionSymbol = null) + { + invocationExpressionSymbol = invocationExpressionSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; + + if (invocationExpression == null || invocationExpressionSymbol == null || invocationExpressionSymbol.ContainingAssembly.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.Ordinal) == false) + { + return Enumerable.Empty(); + } + + if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteDoMethod, StringComparison.Ordinal)) + { + var parentInvocationExpression = GetParentInvocationExpression(invocationExpression); + return FindForWhenExpression(syntaxNodeContext, parentInvocationExpression); + } + + if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenMethod, StringComparison.Ordinal) || + invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenForAnyArgsMethod, StringComparison.Ordinal)) + { + return FindForWhenExpression(syntaxNodeContext, invocationExpression, invocationExpressionSymbol); + } + + if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteAndDoesMethod, StringComparison.Ordinal)) + { + var substitution = FindForAndDoesExpression(syntaxNodeContext, invocationExpression, invocationExpressionSymbol); + return substitution != null ? new[] { substitution } : Enumerable.Empty(); + } + + var standardSubstitution = FindForStandardSubstitution(invocationExpression, invocationExpressionSymbol); + + return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); + } + + public abstract IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, TInvocationExpressionSyntax whenInvocationExpression, IMethodSymbol whenInvocationSymbol = null); + + public abstract SyntaxNode FindForAndDoesExpression(SyntaxNodeAnalysisContext syntaxNodeContext, TInvocationExpressionSyntax invocationExpression, IMethodSymbol invocationExpressionSymbol); + + protected abstract TInvocationExpressionSyntax GetParentInvocationExpression(TInvocationExpressionSyntax invocationExpressionSyntax); + + protected abstract SyntaxNode FindForStandardSubstitution(TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol); + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs index 6046999a..8a656c9d 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -19,38 +19,6 @@ public CallInfoAnalyzer() protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - protected override SyntaxNode GetSubstituteCall(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) - { - if (methodSymbol.IsExtensionMethod) - { - switch (methodSymbol.MethodKind) - { - case MethodKind.ReducedExtension: - return invocationExpressionSyntax.Expression.DescendantNodes().First(); - case MethodKind.Ordinary: - return invocationExpressionSyntax.ArgumentList.Arguments.First().GetExpression(); - default: - return null; - } - } - - var parentInvocation = invocationExpressionSyntax.GetParentInvocationExpression(); - - if (parentInvocation == null) - { - return null; - } - - var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(parentInvocation); - - if (symbol.Symbol is IMethodSymbol mSymbol && mSymbol.ReducedFrom == null) - { - return parentInvocation.ArgumentList.Arguments.First().GetExpression(); - } - - return parentInvocation.Expression.DescendantNodes().First(); - } - protected override IEnumerable GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) { return invocationExpressionSyntax.ArgumentList.Arguments.Select(arg => arg.GetExpression()); @@ -61,6 +29,11 @@ protected override AbstractCallInfoFinder GetSubstitutionNodeFinder() + { + return new SubstitutionNodeFinder(); + } + protected override SyntaxNode GetCastTypeExpression(InvocationExpressionSyntax indexerExpressionSyntax) { if (indexerExpressionSyntax.Parent is CastExpressionSyntax castExpressionSyntax) diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs deleted file mode 100644 index 96f904bf..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoDoAnalyzer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared.Extensions; -using NSubstitute.Analyzers.VisualBasic.Extensions; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers -{ - [DiagnosticAnalyzer(LanguageNames.VisualBasic)] - internal class CallInfoDoAnalyzer : CallInfoAnalyzer - { - private readonly Lazy _whenSubstituteCallFinderProxy = new Lazy(() => new WhenSubstituteCallFinder()); - - private WhenSubstituteCallFinder WhenSubstituteCallFinder => _whenSubstituteCallFinderProxy.Value; - - protected override bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax syntax, IMethodSymbol methodSymbol) - { - if (methodSymbol.Name != "Do") - { - return false; - } - - var allArguments = GetArgumentExpressions(syntax); - return allArguments.Any(arg => syntaxNodeContext.SemanticModel.GetTypeInfo(arg).IsCallInfoDelegate(syntaxNodeContext.SemanticModel)); - } - - protected override SyntaxNode GetSubstituteCall(SyntaxNodeAnalysisContext syntaxNodeContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) - { - var parentInvocationExpression = invocationExpressionSyntax.GetParentInvocationExpression(); - - if (parentInvocationExpression == null) - { - return null; - } - - return WhenSubstituteCallFinder.Find(syntaxNodeContext, parentInvocationExpression).FirstOrDefault(); - } - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs index b701f842..5029b031 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs @@ -19,13 +19,9 @@ public NonSubstitutableMemberWhenAnalyzer() protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - private readonly Lazy _whenSubstituteCallFinderProxy = new Lazy(() => new WhenSubstituteCallFinder()); - - private WhenSubstituteCallFinder WhenSubstituteCallFinder => _whenSubstituteCallFinderProxy.Value; - - protected override IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) + protected override AbstractSubstitutionNodeFinder GetSubstitutionNodeFinder() { - return WhenSubstituteCallFinder.Find(syntaxNodeAnalysisContext, invocationExpressionSyntax, methodSymbol); + return new SubstitutionNodeFinder(); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs similarity index 53% rename from src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs rename to src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index ae137921..477b977a 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WhenSubstituteCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -4,26 +4,68 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; +using NSubstitute.Analyzers.VisualBasic.Extensions; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers { - internal class WhenSubstituteCallFinder + internal class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder { - public IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, ISymbol whenInvocationSymbol = null) + public override IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, IMethodSymbol whenInvocationSymbol = null) { - if ((whenInvocationSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(whenInvocationExpression).Symbol) is IMethodSymbol parentInvocationSymbol) + if (whenInvocationExpression == null) { - var argumentExpression = parentInvocationSymbol.MethodKind == MethodKind.ReducedExtension - ? whenInvocationExpression.ArgumentList.Arguments.First().GetExpression() - : whenInvocationExpression.ArgumentList.Arguments.Skip(1).First().GetExpression(); + return Enumerable.Empty(); + } + + whenInvocationSymbol = whenInvocationSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(whenInvocationExpression).Symbol as IMethodSymbol; + + if (whenInvocationSymbol == null) + { + return Enumerable.Empty(); + } - return Find(syntaxNodeContext, argumentExpression); + var argumentExpression = whenInvocationSymbol.MethodKind == MethodKind.ReducedExtension + ? whenInvocationExpression.ArgumentList.Arguments.First().GetExpression() + : whenInvocationExpression.ArgumentList.Arguments.Skip(1).First().GetExpression(); + + return FindForWhenExpression(syntaxNodeContext, argumentExpression); + } + + public override SyntaxNode FindForAndDoesExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax invocationExpression, IMethodSymbol invocationExpressionSymbol) + { + var parentInvocationExpression = invocationExpression?.GetParentInvocationExpression(); + if (parentInvocationExpression == null) + { + return null; } - return null; + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(parentInvocationExpression); + + return symbol.Symbol is IMethodSymbol methodSymbol && methodSymbol.ReducedFrom == null + ? parentInvocationExpression.ArgumentList.Arguments.First().GetExpression() + : parentInvocationExpression.Expression.DescendantNodes().First(); + } + + protected override InvocationExpressionSyntax GetParentInvocationExpression(InvocationExpressionSyntax invocationExpressionSyntax) + { + return invocationExpressionSyntax.GetParentInvocationExpression(); + } + + protected override SyntaxNode FindForStandardSubstitution(InvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol invocationExpressionSymbol) + { + switch (invocationExpressionSymbol.MethodKind) + { + case MethodKind.ReducedExtension: + return invocationExpressionSyntax.Expression.DescendantNodes().First(); + case MethodKind.Ordinary: + return invocationExpressionSyntax.ArgumentList.Arguments.First().GetExpression(); + default: + return null; + } } - private IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) + private IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) { SyntaxNode body = null; switch (argumentSyntax) @@ -49,7 +91,7 @@ private IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext break; case UnaryExpressionSyntax unaryExpressionSyntax: - foreach (var syntaxNode in Find(syntaxNodeContext, unaryExpressionSyntax.Operand)) + foreach (var syntaxNode in FindForWhenExpression(syntaxNodeContext, unaryExpressionSyntax.Operand)) { yield return syntaxNode; } @@ -69,7 +111,7 @@ private IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext } innerNode = innerNode ?? syntaxNode; - foreach (var expressionsForAnalysy in Find(syntaxNodeContext, innerNode)) + foreach (var expressionsForAnalysy in FindForWhenExpression(syntaxNodeContext, innerNode)) { yield return expressionsForAnalysy; } @@ -105,7 +147,7 @@ private IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext IEnumerable IterateStatements(IEnumerable statements) { - return statements.SelectMany(statement => Find(syntaxNodeContext, statement)); + return statements.SelectMany(statement => FindForWhenExpression(syntaxNodeContext, statement)); } } } diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs similarity index 99% rename from tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs index 36c8784d..ec6ff828 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoDoAnalyzerTests +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoAnalyzerTests { [CombinatoryData("When", "WhenForAnyArgs")] - public class DoMethodPrecededByExtensionMethodTests : CallInfoDoAnalyzerVerifier + public class DoMethodPrecededByExtensionMethodTests : CallInfoDiagnosticVerifier { public override async Task ReportsNoDiagnostics_WhenSubstituteMethodCannotBeInferred(string method, string call, string argAccess) { diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs similarity index 99% rename from tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs index 291dc802..2abcd9bf 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoDoAnalyzerTests +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoAnalyzerTests { [CombinatoryData("SubstituteExtensions.When", "SubstituteExtensions.WhenForAnyArgs")] - public class DoMethodPrecededByOrdinaryMethodTests : CallInfoDoAnalyzerVerifier + public class DoMethodPrecededByOrdinaryMethodTests : CallInfoDiagnosticVerifier { public override async Task ReportsNoDiagnostics_WhenSubstituteMethodCannotBeInferred(string method, string call, string argAccess) { diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs deleted file mode 100644 index 27fc0c9d..00000000 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; -using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; -using NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoAnalyzerTests; -using NSubstitute.Analyzers.Tests.Shared.Extensibility; - -namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.CallInfoDoAnalyzerTests -{ - public abstract class CallInfoDoAnalyzerVerifier : CallInfoDiagnosticVerifier - { - protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() - { - return new CallInfoDoAnalyzer(); - } - } -} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs similarity index 99% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs index c9e35e05..b1e893e3 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByExtensionMethodTests.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoDoAnalyzerTests +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoAnalyzerTests { [CombinatoryData("When", "WhenForAnyArgs")] - public class DoMethodPrecededByExtensionMethodTests : CallInfoDoAnalyzerVerifier + public class DoMethodPrecededByExtensionMethodTests : CallInfoDiagnosticVerifier { public override async Task ReportsNoDiagnostics_WhenSubstituteMethodCannotBeInferred(string method, string call, string argAccess) { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs similarity index 99% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs index 76ea21e1..35f2c5be 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoDoAnalyzerTests +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoAnalyzerTests { [CombinatoryData("SubstituteExtensions.When", "SubstituteExtensions.WhenForAnyArgs")] - public class DoMethodPrecededByOrdinaryMethodTests : CallInfoDoAnalyzerVerifier + public class DoMethodPrecededByOrdinaryMethodTests : CallInfoDiagnosticVerifier { public override async Task ReportsNoDiagnostics_WhenSubstituteMethodCannotBeInferred(string method, string call, string argAccess) { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs deleted file mode 100644 index 7f6c0954..00000000 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoDoAnalyzerTests/CallInfoDoAnalyzerVerifier.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.CodeAnalysis.Diagnostics; -using NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoAnalyzerTests; -using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.CallInfoDoAnalyzerTests -{ - public abstract class CallInfoDoAnalyzerVerifier : CallInfoDiagnosticVerifier - { - protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() - { - return new CallInfoDoAnalyzer(); - } - } -} \ No newline at end of file