-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[GH-16] - non virtual received calls
- Loading branch information
Showing
47 changed files
with
13,476 additions
and
29 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonVirtualSetupReceivedAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using NSubstitute.Analyzers.Shared; | ||
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; | ||
|
||
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
internal class NonVirtualSetupReceivedAnalyzer : AbstractNonVirtualSetupReceivedAnalyzer<SyntaxKind> | ||
{ | ||
protected override ImmutableArray<Parent> PossibleParents { get; } = ImmutableArray.Create( | ||
Parent.Create<MemberAccessExpressionSyntax>(), | ||
Parent.Create<InvocationExpressionSyntax>(), | ||
Parent.Create<ElementAccessExpressionSyntax>()); | ||
|
||
protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; | ||
|
||
public NonVirtualSetupReceivedAnalyzer() | ||
: base(new DiagnosticDescriptorsProvider()) | ||
{ | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...ubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonVirtualSetupReceivedAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
using System; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using NSubstitute.Analyzers.Shared.Extensions; | ||
|
||
namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers | ||
{ | ||
internal abstract class AbstractNonVirtualSetupReceivedAnalyzer<TSyntaxKind> : AbstractDiagnosticAnalyzer | ||
where TSyntaxKind : struct | ||
{ | ||
private static readonly ImmutableHashSet<string> MethodNames = ImmutableHashSet.Create( | ||
MetadataNames.NSubstituteReceivedMethod, | ||
MetadataNames.NSubstituteReceivedWithAnyArgsMethod, | ||
MetadataNames.NSubstituteDidNotReceiveMethod, | ||
MetadataNames.NSubstituteDidNotReceiveWithAnyArgsMethod); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptorsProvider.NonVirtualReceivedSetupSpecification); | ||
|
||
protected AbstractNonVirtualSetupReceivedAnalyzer(IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) | ||
: base(diagnosticDescriptorsProvider) | ||
{ | ||
} | ||
|
||
protected abstract ImmutableArray<Parent> PossibleParents { get; } | ||
|
||
protected abstract TSyntaxKind InvocationExpressionKind { get; } | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.RegisterSyntaxNodeAction(AnalyzeInvocation, InvocationExpressionKind); | ||
} | ||
|
||
private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) | ||
{ | ||
var invocationExpression = syntaxNodeContext.Node; | ||
var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); | ||
|
||
if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) | ||
{ | ||
return; | ||
} | ||
|
||
var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol; | ||
if (methodSymbol == null) | ||
{ | ||
return; | ||
} | ||
|
||
if (IsReceivedLikeMethod(syntaxNodeContext, invocationExpression, methodSymbol.Name) == false) | ||
{ | ||
return; | ||
} | ||
|
||
var parentNode = GetKnownParent(invocationExpression); | ||
|
||
if (parentNode == null) | ||
{ | ||
return; | ||
} | ||
|
||
var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(parentNode); | ||
|
||
if (symbolInfo.Symbol == null) | ||
{ | ||
return; | ||
} | ||
|
||
if (symbolInfo.Symbol.CanBeSetuped()) | ||
{ | ||
return; | ||
} | ||
|
||
var diagnostic = Diagnostic.Create( | ||
DiagnosticDescriptorsProvider.NonVirtualReceivedSetupSpecification, | ||
invocationExpression.GetLocation(), | ||
symbolInfo.Symbol.Name); | ||
|
||
syntaxNodeContext.ReportDiagnostic(diagnostic); | ||
} | ||
|
||
private static bool IsReceivedLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntax, string memberName) | ||
{ | ||
if (MethodNames.Contains(memberName) == false) | ||
{ | ||
return false; | ||
} | ||
|
||
var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntax); | ||
|
||
return symbol.Symbol?.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.Ordinal) == true && | ||
symbol.Symbol?.ContainingType?.ToString().Equals(MetadataNames.NSubstituteSubstituteExtensionsFullTypeName, StringComparison.Ordinal) == true; | ||
} | ||
|
||
private SyntaxNode GetKnownParent(SyntaxNode receivedSyntaxNode) | ||
{ | ||
var typeInfo = receivedSyntaxNode.Parent.GetType().GetTypeInfo(); | ||
|
||
if (PossibleParents.Any(parent => parent.Type.GetTypeInfo().IsAssignableFrom(typeInfo))) | ||
{ | ||
return receivedSyntaxNode.Parent; | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonVirtualSetupReceivedAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis.VisualBasic; | ||
using Microsoft.CodeAnalysis.VisualBasic.Syntax; | ||
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; | ||
|
||
namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.VisualBasic)] | ||
internal class NonVirtualSetupReceivedAnalyzer : AbstractNonVirtualSetupReceivedAnalyzer<SyntaxKind> | ||
{ | ||
protected override ImmutableArray<Parent> PossibleParents { get; } = ImmutableArray.Create( | ||
Parent.Create<MemberAccessExpressionSyntax>(), | ||
Parent.Create<InvocationExpressionSyntax>()); | ||
|
||
protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; | ||
|
||
public NonVirtualSetupReceivedAnalyzer() | ||
: base(new DiagnosticDescriptorsProvider()) | ||
{ | ||
} | ||
} | ||
} |
Oops, something went wrong.