Skip to content

Commit

Permalink
[GH-76] - enclosing substitution node finder in class, less code dupl…
Browse files Browse the repository at this point in the history
…ication across finders
  • Loading branch information
tpodolak committed Apr 2, 2019
1 parent 43d48ed commit 0929c58
Show file tree
Hide file tree
Showing 18 changed files with 276 additions and 296 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExpressionSyntax> GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax)
{
return invocationExpressionSyntax.ArgumentList.Arguments.Select(arg => arg.Expression);
Expand All @@ -61,6 +29,11 @@ protected override AbstractCallInfoFinder<InvocationExpressionSyntax, ElementAcc
return new CallInfoCallFinder();
}

protected override AbstractSubstitutionNodeFinder<InvocationExpressionSyntax> GetSubstitutionNodeFinder()
{
return new SubstitutionNodeFinder();
}

protected override SyntaxNode GetCastTypeExpression(ElementAccessExpressionSyntax indexerExpressionSyntax)
{
switch (indexerExpressionSyntax.Parent)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@ public NonSubstitutableMemberWhenAnalyzer()

protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression;

private readonly Lazy<WhenSubstituteCallFinder> _whenSubstituteCallFinderProxy = new Lazy<WhenSubstituteCallFinder>(() => new WhenSubstituteCallFinder());

private WhenSubstituteCallFinder WhenSubstituteCallFinder => _whenSubstituteCallFinderProxy.Value;

protected override IEnumerable<SyntaxNode> GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax)
protected override AbstractSubstitutionNodeFinder<InvocationExpressionSyntax> GetSubstitutionNodeFinder()
{
return WhenSubstituteCallFinder.Find(syntaxNodeAnalysisContext, invocationExpressionSyntax, methodSymbol);
return new SubstitutionNodeFinder();
}
}
}
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Finds nodes which are considered to be a part of substitution call. For instance substitute.Bar().Returns(1) will return substitute.Bar()
/// </summary>
internal class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder<InvocationExpressionSyntax>
{
public override IEnumerable<SyntaxNode> FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, IMethodSymbol whenInvocationSymbol = null)
{
if (whenInvocationExpression == null)
{
return Enumerable.Empty<SyntaxNode>();
}

whenInvocationSymbol = whenInvocationSymbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(whenInvocationExpression).Symbol as IMethodSymbol;

if (whenInvocationSymbol == null)
{
return Enumerable.Empty<SyntaxNode>();
}

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<SyntaxNode> 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;
}
}
}
}

This file was deleted.

Loading

0 comments on commit 0929c58

Please sign in to comment.