Skip to content

Commit

Permalink
[GH-153] - using Operation API for substitution node finder
Browse files Browse the repository at this point in the history
  • Loading branch information
tpodolak committed Dec 20, 2020
1 parent e3f98bd commit 0912c72
Show file tree
Hide file tree
Showing 23 changed files with 68 additions and 113 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers;

namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer<SyntaxKind, InvocationExpressionSyntax>
internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer<SyntaxKind>
{
protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer<SyntaxKind, InvocationExpressionSyntax, MemberAccessExpressionSyntax, BlockSyntax>
internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer<SyntaxKind, MemberAccessExpressionSyntax, BlockSyntax>
{
private static ImmutableArray<int> IgnoredPaths { get; } =
ImmutableArray.Create((int)SyntaxKind.Argument, (int)SyntaxKind.VariableDeclarator, (int)SyntaxKind.AddAssignmentExpression);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers;

namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer<SyntaxKind, InvocationExpressionSyntax>
internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer<SyntaxKind>
{
public NonSubstitutableMemberWhenAnalyzer()
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class ReEntrantCallFinder : AbstractReEntrantCallFinder<InvocationExpre
{
public static ReEntrantCallFinder Instance { get; } = new ReEntrantCallFinder(SubstitutionNodeFinder.Instance);

private ReEntrantCallFinder(ISubstitutionNodeFinder<InvocationExpressionSyntax> substitutionNodeFinder)
private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder)
: base(substitutionNodeFinder)
{
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers;

namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer<SyntaxKind, InvocationExpressionSyntax>
internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer<SyntaxKind>
{
public ReceivedInReceivedInOrderAnalyzer()
: base(SubstitutionNodeFinder.Instance, CSharp.DiagnosticDescriptorsProvider.Instance)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using NSubstitute.Analyzers.CSharp.Extensions;
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers;
using NSubstitute.Analyzers.Shared.Extensions;

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>
internal class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder
{
public static SubstitutionNodeFinder Instance { get; } = new SubstitutionNodeFinder();

private SubstitutionNodeFinder()
{
}

public override IEnumerable<SyntaxNode> FindForReceivedInOrderExpression(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax receivedInOrderExpression, IMethodSymbol receivedInOrderInvocationSymbol = null)
protected override SyntaxNode GetSubstitutionActualNode(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode)
{
var argumentExpression = receivedInOrderExpression.ArgumentList.Arguments.First();

return FindInvocations(syntaxNodeContext, argumentExpression.Expression).Select(syntax =>
syntax.GetSubstitutionActualNode(node => syntaxNodeContext.SemanticModel.GetSymbolInfo(node).Symbol));
}

protected override IEnumerable<SyntaxNode> FindForWhenExpressionInternal(SyntaxNodeAnalysisContext syntaxNodeContext, InvocationExpressionSyntax whenInvocationExpression, IMethodSymbol whenInvocationSymbol)
{
var argumentExpression = whenInvocationSymbol.MethodKind == MethodKind.ReducedExtension
? whenInvocationExpression.ArgumentList.Arguments.First().Expression
: whenInvocationExpression.ArgumentList.Arguments.Skip(1).First().Expression;

return FindInvocations(syntaxNodeContext, argumentExpression).Select(syntax => syntax.GetSubstitutionActualNode(node => syntaxNodeContext.SemanticModel.GetSymbolInfo(node).Symbol));
return syntaxNode.GetSubstitutionActualNode(node => syntaxNodeContext.SemanticModel.GetSymbolInfo(node).Symbol);
}

private IEnumerable<SyntaxNode> FindInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax)
protected override IEnumerable<SyntaxNode> FindInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax)
{
SyntaxNode body = null;
switch (argumentSyntax)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ private static AnalyzersSettings GetUpdatedAnalyzersOptions(CodeFixContext conte
{
var options = context.Document.Project.AnalyzerOptions.GetSettings(default(CancellationToken));
var target = CreateSuppressionTarget(symbol);
options.Suppressions = options.Suppressions ?? new List<Suppression>();
options.Suppressions ??= new List<Suppression>();

var existingSuppression = options.Suppressions.FirstOrDefault(suppression => suppression.Target == target);

if (existingSuppression != null)
{
existingSuppression.Rules = existingSuppression.Rules ?? new List<string>();
existingSuppression.Rules ??= new List<string>();
existingSuppression.Rules.Add(diagnostic.Id);
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ internal abstract class AbstractCallInfoAnalyzer<TSyntaxKind, TInvocationExpress
where TSyntaxKind : struct
{
private readonly ICallInfoFinder<TInvocationExpressionSyntax, TIndexerExpressionSyntax> _callInfoFinder;
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;
private readonly Action<SyntaxNodeAnalysisContext> _analyzeInvocationAction;

protected AbstractCallInfoAnalyzer(
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider,
ICallInfoFinder<TInvocationExpressionSyntax, TIndexerExpressionSyntax> callInfoFinder,
ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder)
ISubstitutionNodeFinder substitutionNodeFinder)
: base(diagnosticDescriptorsProvider)
{
_callInfoFinder = callInfoFinder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,8 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext)

private bool IsAssigned(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, TIndexerExpressionSyntax indexerExpressionSyntax)
{
if (!(syntaxNodeAnalysisContext.SemanticModel.GetOperation(indexerExpressionSyntax) is IPropertyReferenceOperation propertyReferenceOperation))
{
return false;
}

if (propertyReferenceOperation.Property.ContainingType.IsCallInfoSymbol() == false)
{
return false;
}

return propertyReferenceOperation.Parent is ISimpleAssignmentOperation;
return syntaxNodeAnalysisContext.SemanticModel.GetOperation(indexerExpressionSyntax) is IPropertyReferenceOperation propertyReferenceOperation &&
propertyReferenceOperation.Parent is ISimpleAssignmentOperation;
}

private IEnumerable<TIndexerExpressionSyntax> FindCallInfoIndexers(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@

namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers
{
internal abstract class AbstractNonSubstitutableMemberAnalyzer<TSyntaxKind, TInvocationExpressionSyntax> : AbstractNonSubstitutableSetupAnalyzer
where TInvocationExpressionSyntax : SyntaxNode
internal abstract class AbstractNonSubstitutableMemberAnalyzer<TSyntaxKind> : AbstractNonSubstitutableSetupAnalyzer
where TSyntaxKind : struct
{
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;

private readonly Action<SyntaxNodeAnalysisContext> _analyzeInvocationAction;

Expand All @@ -23,7 +22,7 @@ internal abstract class AbstractNonSubstitutableMemberAnalyzer<TSyntaxKind, TInv

protected AbstractNonSubstitutableMemberAnalyzer(
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider,
ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder,
ISubstitutionNodeFinder substitutionNodeFinder,
INonSubstitutableMemberAnalysis nonSubstitutableMemberAnalysis)
: base(diagnosticDescriptorsProvider, nonSubstitutableMemberAnalysis)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@

namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers
{
internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer<TSyntaxKind, TInvocationExpressionSyntax, TMemberAccessExpressionSyntax, TBlockStatementSyntax> : AbstractNonSubstitutableSetupAnalyzer
internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer<TSyntaxKind, TMemberAccessExpressionSyntax, TBlockStatementSyntax> : AbstractNonSubstitutableSetupAnalyzer
where TSyntaxKind : struct
where TInvocationExpressionSyntax : SyntaxNode
where TMemberAccessExpressionSyntax : SyntaxNode
where TBlockStatementSyntax : SyntaxNode
{
Expand All @@ -21,10 +20,10 @@ internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer<TS
protected abstract ImmutableArray<int> IgnoredAncestorPaths { get; }

private readonly Action<SyntaxNodeAnalysisContext> _analyzeInvocationAction;
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;

protected AbstractNonSubstitutableMemberReceivedInOrderAnalyzer(
ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder,
ISubstitutionNodeFinder substitutionNodeFinder,
INonSubstitutableMemberAnalysis nonSubstitutableMemberAnalysis,
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider)
: base(diagnosticDescriptorsProvider, nonSubstitutableMemberAnalysis)
Expand All @@ -51,23 +50,18 @@ protected override Location GetSubstitutionNodeActualLocation(in NonSubstitutabl

private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext)
{
var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node;
var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression);

if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method)
if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation invocationOperation))
{
return;
}

if (methodSymbolInfo.Symbol.IsReceivedInOrderMethod() == false)
if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false)
{
return;
}

foreach (var syntaxNode in _substitutionNodeFinder.FindForReceivedInOrderExpression(
syntaxNodeContext,
invocationExpression,
(IMethodSymbol)methodSymbolInfo.Symbol).Where(node => ShouldAnalyzeNode(syntaxNodeContext.SemanticModel, node)))
foreach (var syntaxNode in _substitutionNodeFinder.FindForReceivedInOrderExpression(syntaxNodeContext, invocationOperation)
.Where(node => ShouldAnalyzeNode(syntaxNodeContext.SemanticModel, node)))
{
var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntaxNode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@

namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers
{
internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer<TSyntaxKind, TInvocationExpressionSyntax> : AbstractNonSubstitutableSetupAnalyzer
where TInvocationExpressionSyntax : SyntaxNode
internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer<TSyntaxKind> : AbstractNonSubstitutableSetupAnalyzer
where TSyntaxKind : struct, Enum
{
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }

Expand All @@ -21,7 +20,7 @@ internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer<TSyntaxKind,

protected AbstractNonSubstitutableMemberWhenAnalyzer(
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider,
ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder,
ISubstitutionNodeFinder substitutionNodeFinder,
INonSubstitutableMemberAnalysis nonSubstitutableMemberAnalysis)
: base(diagnosticDescriptorsProvider, nonSubstitutableMemberAnalysis)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ internal abstract class AbstractReEntrantCallFinder<TInvocationExpressionSyntax,
where TInvocationExpressionSyntax : SyntaxNode
where TIdentifierExpressionSyntax : SyntaxNode
{
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;

protected AbstractReEntrantCallFinder(ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder)
protected AbstractReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder)
{
_substitutionNodeFinder = substitutionNodeFinder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using NSubstitute.Analyzers.Shared.Extensions;

namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers
{
internal abstract class AbstractReceivedInReceivedInOrderAnalyzer<TSyntaxKind, TInvocationExpressionSyntax> : AbstractDiagnosticAnalyzer
internal abstract class AbstractReceivedInReceivedInOrderAnalyzer<TSyntaxKind> : AbstractDiagnosticAnalyzer
where TSyntaxKind : struct
where TInvocationExpressionSyntax : SyntaxNode
{
private readonly ISubstitutionNodeFinder<TInvocationExpressionSyntax> _substitutionNodeFinder;
private readonly ISubstitutionNodeFinder _substitutionNodeFinder;
private readonly Action<SyntaxNodeAnalysisContext> _analyzeInvocationAction;

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }

protected AbstractReceivedInReceivedInOrderAnalyzer(
ISubstitutionNodeFinder<TInvocationExpressionSyntax> substitutionNodeFinder,
ISubstitutionNodeFinder substitutionNodeFinder,
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider)
: base(diagnosticDescriptorsProvider)
{
Expand All @@ -34,23 +34,19 @@ protected override void InitializeAnalyzer(AnalysisContext context)

private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext)
{
var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node;
var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression);

if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method)
if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation invocationOperation))
{
return;
}

if (methodSymbolInfo.Symbol.IsReceivedInOrderMethod() == false)
if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false)
{
return;
}

foreach (var syntaxNode in _substitutionNodeFinder.FindForReceivedInOrderExpression(
syntaxNodeContext,
invocationExpression,
(IMethodSymbol)methodSymbolInfo.Symbol))
invocationOperation))
{
var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntaxNode);

Expand Down
Loading

0 comments on commit 0912c72

Please sign in to comment.