From 9d93bd187e6b62ced55a41a84c4f16d4f3a1ea56 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 5 Jul 2022 01:17:38 +0200 Subject: [PATCH 01/35] GH-153 - using operations api in NonSubstitutableMemberWhenAnalyzer --- .../NonSubstitutableMemberAnalyzer.cs | 4 +- .../NonSubstitutableMemberReceivedAnalyzer.cs | 6 +- .../NonSubstitutableMemberWhenAnalyzer.cs | 5 +- .../Extensions/SyntaxExtensions.cs | 12 -- .../AbstractNonSubstitutableMemberAnalysis.cs | 67 +++++++--- .../AbstractNonSubstitutableMemberAnalyzer.cs | 43 ++----- ...tNonSubstitutableMemberReceivedAnalyzer.cs | 27 ++--- ...stitutableMemberReceivedInOrderAnalyzer.cs | 13 +- ...tractNonSubstitutableMemberWhenAnalyzer.cs | 25 ++-- .../AbstractNonSubstitutableSetupAnalyzer.cs | 46 +++++++ .../AbstractSubstitutionNodeFinder.cs | 114 ++++++++++++++++-- .../INonSubstitutableMemberAnalysis.cs | 7 ++ .../ISubstitutionNodeFinder.cs | 4 +- .../NonSubstitutableMemberAnalysis.cs | 85 ------------- .../SyntaxNodeAnalysisContextExtensions.cs | 24 ++-- .../NonSubstitutableMemberAnalyzer.cs | 4 +- .../NonSubstitutableMemberReceivedAnalyzer.cs | 6 +- .../NonSubstitutableMemberWhenAnalyzer.cs | 5 +- 18 files changed, 260 insertions(+), 237 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs index c4de6b6e..b59aa018 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs @@ -6,10 +6,8 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer +internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer { - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public NonSubstitutableMemberAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance) { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs index 3a0da023..a9eda0c2 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs @@ -1,16 +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 NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer +internal sealed class NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer { - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public NonSubstitutableMemberReceivedAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, NonSubstitutableMemberAnalysis.Instance) { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs index 4bcb2923..8ca68614 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs @@ -1,17 +1,14 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer +internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer { public NonSubstitutableMemberWhenAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs b/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs index b08878e2..b1ea2200 100644 --- a/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs +++ b/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs @@ -1,6 +1,5 @@ using System; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using NSubstitute.Analyzers.Shared.Extensions; @@ -8,17 +7,6 @@ namespace NSubstitute.Analyzers.CSharp.Extensions; internal static class SyntaxExtensions { - private static readonly int[] ParentInvocationKindHierarchy = - { - (int)SyntaxKind.SimpleMemberAccessExpression, - (int)SyntaxKind.InvocationExpression - }; - - public static InvocationExpressionSyntax GetParentInvocationExpression(this SyntaxNode node) - { - return node.GetParentNode(ParentInvocationKindHierarchy) as InvocationExpressionSyntax; - } - public static SyntaxNode GetSubstitutionActualNode(this SyntaxNode node, Func symbolProvider) { return node.GetSubstitutionActualNode(symbolProvider); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs index 1721d2b9..a6a4bb3e 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs @@ -2,6 +2,7 @@ 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; @@ -13,11 +14,34 @@ internal abstract class AbstractNonSubstitutableMemberAnalysis : INonSubstitutab public NonSubstitutableMemberAnalysisResult Analyze( in SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode accessedMember, - ISymbol symbol = null) + ISymbol symbol = null) => + Analyze(accessedMember, symbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(accessedMember).Symbol); + + public NonSubstitutableMemberAnalysisResult Analyze(IInvocationOperation invocationOperation, ISymbol symbol = null) + { + return Analyze( + invocationOperation.Syntax, + symbol ?? invocationOperation.TargetMethod); + } + + public NonSubstitutableMemberAnalysisResult Analyze(IOperation operation) + { + var symbol = ExtractSymbol(operation); + + return Analyze(operation.Syntax, symbol); + } + + protected virtual bool CanBeSubstituted( + SyntaxNode accessedMember, + ISymbol symbol) { - var accessedSymbol = symbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(accessedMember).Symbol; + return !KnownNonVirtualSyntaxKinds.Contains(accessedMember.GetType()) && + CanBeSubstituted(symbol); + } - if (accessedSymbol == null) + private NonSubstitutableMemberAnalysisResult Analyze(SyntaxNode accessedMember, ISymbol symbol) + { + if (symbol == null) { return new NonSubstitutableMemberAnalysisResult( nonVirtualMemberSubstitution: KnownNonVirtualSyntaxKinds.Contains(accessedMember.GetType()), @@ -27,43 +51,34 @@ public NonSubstitutableMemberAnalysisResult Analyze( memberName: accessedMember.ToString()); } - var canBeSubstituted = CanBeSubstituted(syntaxNodeContext, accessedMember, accessedSymbol); + var canBeSubstituted = CanBeSubstituted(accessedMember, symbol); if (canBeSubstituted == false) { return new NonSubstitutableMemberAnalysisResult( nonVirtualMemberSubstitution: true, internalMemberSubstitution: false, - symbol: accessedSymbol, + symbol: symbol, member: accessedMember, - memberName: accessedSymbol.Name); + memberName: symbol.Name); } - if (accessedSymbol.MemberVisibleToProxyGenerator() == false) + if (symbol.MemberVisibleToProxyGenerator() == false) { return new NonSubstitutableMemberAnalysisResult( nonVirtualMemberSubstitution: false, internalMemberSubstitution: true, - symbol: accessedSymbol, + symbol: symbol, member: accessedMember, - memberName: accessedSymbol.Name); + memberName: symbol.Name); } return new NonSubstitutableMemberAnalysisResult( nonVirtualMemberSubstitution: false, internalMemberSubstitution: false, - symbol: accessedSymbol, + symbol: symbol, member: accessedMember, - memberName: accessedSymbol.Name); - } - - protected virtual bool CanBeSubstituted( - SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode accessedMember, - ISymbol symbol) - { - return !KnownNonVirtualSyntaxKinds.Contains(accessedMember.GetType()) && - CanBeSubstituted(symbol); + memberName: symbol.Name); } private static bool CanBeSubstituted(ISymbol symbol) @@ -84,4 +99,16 @@ private static bool IsVirtual(ISymbol symbol) return isVirtual; } + + private static ISymbol ExtractSymbol(IOperation operation) + { + var symbol = operation switch + { + IInvocationOperation invocationOperation => invocationOperation.TargetMethod, + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, + IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), + _ => null + }; + return symbol; + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs index 4fe22964..4a799133 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs @@ -7,17 +7,14 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractNonSubstitutableMemberAnalyzer : AbstractNonSubstitutableSetupAnalyzer - where TSyntaxKind : struct +internal abstract class AbstractNonSubstitutableMemberAnalyzer : AbstractNonSubstitutableSetupAnalyzer { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; public override ImmutableArray SupportedDiagnostics { get; } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected AbstractNonSubstitutableMemberAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, ISubstitutionNodeFinder substitutionNodeFinder, @@ -36,13 +33,12 @@ protected AbstractNonSubstitutableMemberAnalyzer( protected sealed override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation - invocationOperation)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } @@ -52,38 +48,25 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - AnalyzeMember(syntaxNodeContext, _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation)); + AnalyzeMember(operationAnalysisContext, _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation)); } - private void AnalyzeMember(SyntaxNodeAnalysisContext syntaxNodeContext, IOperation accessedMember) + private void AnalyzeMember(OperationAnalysisContext operationAnalysisContext, IOperation accessedMember) { if (IsValidForAnalysis(accessedMember) == false) { return; } - Analyze(syntaxNodeContext, accessedMember.Syntax); + Analyze(operationAnalysisContext, accessedMember); } - // TODO use switch expressions/pattern matching when GH-179 merged private bool IsValidForAnalysis(IOperation accessedMember) { - if (accessedMember == null) - { - return false; - } - - if (accessedMember is ILocalReferenceOperation) - { - return false; - } - - if (accessedMember is IConversionOperation conversionOperation && - conversionOperation.Operand is ILocalReferenceOperation) - { - return false; - } - - return true; + return accessedMember != null && accessedMember is not ILocalReferenceOperation && + accessedMember is not IConversionOperation + { + Operand: ILocalReferenceOperation + }; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs index 3bc4d44b..4bfa9ead 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs @@ -7,11 +7,9 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractNonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableSetupAnalyzer - where TSyntaxKind : struct - where TMemberAccessExpressionSyntax : SyntaxNode +internal abstract class AbstractNonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableSetupAnalyzer { - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationOperation; public override ImmutableArray SupportedDiagnostics { get; } @@ -20,34 +18,25 @@ protected AbstractNonSubstitutableMemberReceivedAnalyzer( INonSubstitutableMemberAnalysis nonSubstitutableMemberAnalysis) : base(diagnosticDescriptorsProvider, nonSubstitutableMemberAnalysis) { - _analyzeInvocationAction = AnalyzeInvocation; + _analyzeInvocationOperation = AnalyzeInvocation; SupportedDiagnostics = ImmutableArray.Create( DiagnosticDescriptorsProvider.NonVirtualReceivedSetupSpecification, DiagnosticDescriptorsProvider.InternalSetupSpecification); NonVirtualSetupDescriptor = diagnosticDescriptorsProvider.NonVirtualReceivedSetupSpecification; } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationOperation, OperationKind.Invocation); } - protected override Location GetSubstitutionNodeActualLocation(in NonSubstitutableMemberAnalysisResult analysisResult) + private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) { - return analysisResult.Member.GetSubstitutionNodeActualLocation(analysisResult.Symbol); - } - - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) - { - var invocationExpression = syntaxNodeContext.Node; - if (!(syntaxNodeContext.SemanticModel.GetOperation(invocationExpression) is IInvocationOperation - invocationOperation)) + if (syntaxNodeContext.Operation is not IInvocationOperation invocationOperation) { - return; + return; } if (invocationOperation.Parent == null) @@ -60,6 +49,6 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - Analyze(syntaxNodeContext, invocationOperation.Parent.Syntax); + Analyze(syntaxNodeContext, invocationOperation.Parent); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index 56a96fef..b1745eaf 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -134,15 +134,12 @@ operation.Parent is IInvocationOperation invocationOperation && private static ILocalSymbol GetVariableDeclaratorSymbol(IOperation operation) { - switch (operation) + return operation switch { - case IVariableDeclaratorOperation declarator: - return declarator.Symbol; - case IVariableDeclarationOperation declarationOperation: - return declarationOperation.Declarators.FirstOrDefault()?.Symbol; - default: - return null; - } + IVariableDeclaratorOperation declarator => declarator.Symbol, + IVariableDeclarationOperation declarationOperation => declarationOperation.Declarators.FirstOrDefault()?.Symbol, + _ => null + }; } private SyntaxNode FindIgnoredEnclosingExpression(SyntaxNode syntaxNode) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs index c301ee9c..79d45970 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs @@ -7,16 +7,13 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableSetupAnalyzer - where TSyntaxKind : struct, Enum +internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableSetupAnalyzer { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; public override ImmutableArray SupportedDiagnostics { get; } - private readonly Action _analyzeInvocationAction; - - protected abstract TSyntaxKind InvocationExpressionKind { get; } + private readonly Action _analyzeInvocationAction; protected AbstractNonSubstitutableMemberWhenAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -36,13 +33,12 @@ protected AbstractNonSubstitutableMemberWhenAnalyzer( protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation - invocationOperation)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } @@ -52,15 +48,10 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - var expressionsForAnalysys = - _substitutionNodeFinder.FindForWhenExpression(syntaxNodeContext, invocationOperation); - foreach (var analysedSyntax in expressionsForAnalysys) + var operations = _substitutionNodeFinder.FindForWhenExpression(operationAnalysisContext, invocationOperation); + foreach (var operation in operations) { - var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(analysedSyntax); - if (symbolInfo.Symbol != null) - { - Analyze(syntaxNodeContext, analysedSyntax, symbolInfo.Symbol); - } + Analyze(operationAnalysisContext, operation); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs index 480a8a56..90f39e18 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -31,6 +32,26 @@ protected void Analyze(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, Synt } } + protected void Analyze(OperationAnalysisContext operationAnalysisContext, IInvocationOperation operation, ISymbol symbol = null) + { + var analysisResult = _nonSubstitutableMemberAnalysis.Analyze(operation, symbol); + + if (analysisResult.CanBeSubstituted == false) + { + ReportDiagnostics(operationAnalysisContext, in analysisResult); + } + } + + protected void Analyze(OperationAnalysisContext operationAnalysisContext, IOperation operation, ISymbol symbol = null) + { + var analysisResult = _nonSubstitutableMemberAnalysis.Analyze(operation); + + if (analysisResult.CanBeSubstituted == false) + { + ReportDiagnostics(operationAnalysisContext, in analysisResult); + } + } + protected virtual Location GetSubstitutionNodeActualLocation(in NonSubstitutableMemberAnalysisResult analysisResult) { return analysisResult.Member.GetLocation(); @@ -60,4 +81,29 @@ private void ReportDiagnostics( context.ReportDiagnostic(diagnostic); } } + + private void ReportDiagnostics( + OperationAnalysisContext context, + in NonSubstitutableMemberAnalysisResult analysisResult) + { + var location = GetSubstitutionNodeActualLocation(analysisResult); + if (analysisResult.NonVirtualMemberSubstitution) + { + var diagnostic = Diagnostic.Create( + NonVirtualSetupDescriptor, + location, + analysisResult.MemberName); + context.TryReportDiagnostic(diagnostic, analysisResult.Symbol); + } + + if (analysisResult.InternalMemberSubstitution) + { + var diagnostic = Diagnostic.Create( + _internalSetupSpecificationDescriptor, + location, + analysisResult.MemberName); + + context.ReportDiagnostic(diagnostic); + } + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs index dcc0c6f3..5a7151d9 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -10,16 +10,6 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal abstract class AbstractSubstitutionNodeFinder : ISubstitutionNodeFinder { - public IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode invocationExpression, IMethodSymbol invocationExpressionSymbol) - { - if (syntaxNodeContext.SemanticModel.GetOperation(invocationExpression) is IInvocationOperation invocationOperation) - { - return Find(syntaxNodeContext, invocationOperation, invocationExpressionSymbol); - } - - return Enumerable.Empty(); - } - public IEnumerable Find( SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, @@ -64,7 +54,10 @@ public IEnumerable Find( return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); } - public IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol whenInvocationSymbol = null) + public IEnumerable FindForWhenExpression( + SyntaxNodeAnalysisContext syntaxNodeContext, + IInvocationOperation invocationOperation, + IMethodSymbol whenInvocationSymbol = null) { if (invocationOperation == null) { @@ -93,12 +86,31 @@ public IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext s } } + public IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) + { + var whenVisitor = new WhenVisitor(operationAnalysisContext, invocationOperation); + whenVisitor.Visit(); + + var typeSymbol = invocationOperation.TargetMethod.TypeArguments.FirstOrDefault() ?? + invocationOperation.TargetMethod.ReceiverType; + + foreach (var operation in whenVisitor.Operations) + { + var symbol = ExtractSymbol(operation); + + if (symbol != null && ContainsSymbol(typeSymbol, symbol)) + { + yield return operation; + } + } + } + public SyntaxNode FindForAndDoesExpression( SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol invocationExpressionSymbol) { - if (!(invocationOperation.GetSubstituteOperation() is IInvocationOperation parentInvocationExpression)) + if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationExpression) { return null; } @@ -146,4 +158,82 @@ private static IEnumerable GetBaseTypesAndThis(ITypeSymbol type) current = current.BaseType; } } + + private static ISymbol ExtractSymbol(IOperation operation) + { + var symbol = operation switch + { + IInvocationOperation invocationOperation => invocationOperation.TargetMethod, + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, + IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), + _ => null + }; + return symbol; + } + + private class WhenVisitor : OperationWalker + { + private readonly OperationAnalysisContext _operationAnalysisContext; + private readonly IInvocationOperation _whenInvocationOperation; + private readonly List _operations = new List(); + private readonly IDictionary + _semanticModelCache = new Dictionary(1); + + public WhenVisitor( + OperationAnalysisContext operationAnalysisContext, + IInvocationOperation whenInvocationOperation) + { + _operationAnalysisContext = operationAnalysisContext; + _whenInvocationOperation = whenInvocationOperation; + } + + public IReadOnlyList Operations => _operations.AsReadOnly(); + + public void Visit() => Visit(_whenInvocationOperation); + + public override void VisitInvocation(IInvocationOperation operation) + { + if (operation != _whenInvocationOperation) + { + _operations.Add(operation); + } + + base.VisitInvocation(operation); + } + + public override void VisitMethodReference(IMethodReferenceOperation operation) + { + foreach (var methodDeclaringSyntaxReference in operation.Method.DeclaringSyntaxReferences) + { + // TODO async? + var syntaxNode = methodDeclaringSyntaxReference.GetSyntax(); + var semanticModel = GetSemanticModel(syntaxNode.Parent); + var referencedOperation = semanticModel.GetOperation(syntaxNode) ?? + semanticModel.GetOperation(syntaxNode.Parent); + Visit(referencedOperation); + } + + base.VisitMethodReference(operation); + } + + public override void VisitPropertyReference(IPropertyReferenceOperation operation) + { + _operations.Add(operation); + base.VisitPropertyReference(operation); + } + + private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) + { + var syntaxTree = syntaxNode.SyntaxTree; + if (_semanticModelCache.TryGetValue(syntaxTree, out var semanticModel)) + { + return semanticModel; + } + + semanticModel = _operationAnalysisContext.Compilation.GetSemanticModel(syntaxTree); + _semanticModelCache[syntaxTree] = semanticModel; + + return semanticModel; + } + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs index fde7a4eb..7225c7e7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -9,4 +10,10 @@ NonSubstitutableMemberAnalysisResult Analyze( in SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode accessedMember, ISymbol symbol = null); + + NonSubstitutableMemberAnalysisResult Analyze( + IInvocationOperation invocationOperation, + ISymbol symbol = null); + + NonSubstitutableMemberAnalysisResult Analyze(IOperation operation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 7192d658..07f26db6 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -7,12 +7,12 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface ISubstitutionNodeFinder { - IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode invocationExpression, IMethodSymbol invocationExpressionSymbol); - IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol invocationExpressionSymbol = null); IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol whenInvocationSymbol = null); + IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); + IEnumerable FindForReceivedInOrderExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol receivedInOrderInvocationSymbol = null); SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs deleted file mode 100644 index 10e65ac4..00000000 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; -using NSubstitute.Analyzers.Shared.Extensions; - -namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -internal class NonSubstitutableMemberAnalysis : INonSubstitutableMemberAnalysis -{ - public static INonSubstitutableMemberAnalysis Instance { get; } = new NonSubstitutableMemberAnalysis(); - - public NonSubstitutableMemberAnalysisResult Analyze( - in SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode accessedMember, - ISymbol symbol = null) - { - var accessedSymbol = symbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(accessedMember).Symbol; - - if (accessedSymbol == null) - { - return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: syntaxNodeContext.SemanticModel.GetOperation(accessedMember) is ILiteralOperation, - internalMemberSubstitution: false, - symbol: null, - member: accessedMember, - memberName: accessedMember.ToString()); - } - - var canBeSubstituted = CanBeSubstituted(syntaxNodeContext, accessedMember, accessedSymbol); - - if (canBeSubstituted == false) - { - return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: true, - internalMemberSubstitution: false, - symbol: accessedSymbol, - member: accessedMember, - memberName: accessedSymbol.Name); - } - - if (accessedSymbol.MemberVisibleToProxyGenerator() == false) - { - return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: false, - internalMemberSubstitution: true, - symbol: accessedSymbol, - member: accessedMember, - memberName: accessedSymbol.Name); - } - - return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: false, - internalMemberSubstitution: false, - symbol: accessedSymbol, - member: accessedMember, - memberName: accessedSymbol.Name); - } - - protected virtual bool CanBeSubstituted( - SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode accessedMember, - ISymbol symbol) - { - return CanBeSubstituted(symbol); - } - - private static bool CanBeSubstituted(ISymbol symbol) - { - return IsInterfaceMember(symbol) || IsVirtual(symbol); - } - - private static bool IsInterfaceMember(ISymbol symbol) - { - return symbol.ContainingType?.TypeKind == TypeKind.Interface; - } - - private static bool IsVirtual(ISymbol symbol) - { - var isVirtual = symbol.IsVirtual - || (symbol.IsOverride && !symbol.IsSealed) - || symbol.IsAbstract; - - return isVirtual; - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs index ed67c5cf..7fbfbb8a 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs @@ -20,7 +20,7 @@ internal static void TryReportDiagnostic( Diagnostic diagnostic, ISymbol symbol) { - if (IsSuppressed(syntaxNodeContext, diagnostic, symbol)) + if (IsSuppressed(syntaxNodeContext.GetSettings(CancellationToken.None), syntaxNodeContext.Compilation, symbol, diagnostic.Id)) { return; } @@ -28,21 +28,29 @@ internal static void TryReportDiagnostic( syntaxNodeContext.ReportDiagnostic(diagnostic); } - private static bool IsSuppressed( - SyntaxNodeAnalysisContext syntaxNodeContext, + internal static void TryReportDiagnostic( + this OperationAnalysisContext syntaxNodeContext, Diagnostic diagnostic, ISymbol symbol) { - return symbol != null && IsSuppressed(syntaxNodeContext, symbol, diagnostic.Id); + if (IsSuppressed( + syntaxNodeContext.Options.GetSettings(CancellationToken.None), + syntaxNodeContext.Compilation, + symbol, + diagnostic.Id)) + { + return; + } + + syntaxNodeContext.ReportDiagnostic(diagnostic); } private static bool IsSuppressed( - SyntaxNodeAnalysisContext syntaxNodeContext, + AnalyzersSettings analyzersSettings, + Compilation compilation, ISymbol symbol, string diagnosticId) { - var analyzersSettings = syntaxNodeContext.GetSettings(CancellationToken.None); - if (analyzersSettings.Suppressions.Count == 0) { return false; @@ -52,7 +60,7 @@ private static bool IsSuppressed( return analyzersSettings.Suppressions.Where(suppression => suppression.Rules.Contains(diagnosticId)) .SelectMany(suppression => - DocumentationCommentId.GetSymbolsForDeclarationId(suppression.Target, syntaxNodeContext.Compilation)) + DocumentationCommentId.GetSymbolsForDeclarationId(suppression.Target, compilation)) .Any(possibleSymbols.Contains); } diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs index 6787a244..c4ef7b41 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs @@ -6,10 +6,8 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer +internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer { - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public NonSubstitutableMemberAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance) { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs index 9a83e29e..5405b3b7 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedAnalyzer.cs @@ -1,16 +1,12 @@ 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 sealed class NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer +internal sealed class NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer { - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public NonSubstitutableMemberReceivedAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, NonSubstitutableMemberAnalysis.Instance) { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs index 760186c0..bcb445c8 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberWhenAnalyzer.cs @@ -1,17 +1,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer +internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer { public NonSubstitutableMemberWhenAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file From 32f6d63456ea9466c5b735ad440264cafcfd3d2b Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 10 Jul 2022 22:28:50 +0200 Subject: [PATCH 02/35] GH-153 - using operations api in ReceivedInOrderAnalyzer --- ...stitutableMemberReceivedInOrderAnalyzer.cs | 8 +- ...stitutableMemberReceivedInOrderAnalyzer.cs | 86 ++++++------------- .../AbstractSubstitutionNodeFinder.cs | 41 +++++++-- .../ISubstitutionNodeFinder.cs | 2 + .../Extensions/IOperationExtensions.cs | 10 +++ ...stitutableMemberReceivedInOrderAnalyzer.cs | 7 +- 6 files changed, 76 insertions(+), 78 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs index 4fc05f99..4e4929b9 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -1,14 +1,14 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer +internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer { private static ImmutableArray IgnoredPaths { get; } = ImmutableArray.Create((int)SyntaxKind.Argument, (int)SyntaxKind.VariableDeclarator, (int)SyntaxKind.AddAssignmentExpression); @@ -17,8 +17,4 @@ public NonSubstitutableMemberReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override ImmutableArray IgnoredAncestorPaths { get; } = IgnoredPaths; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index b1745eaf..a0930194 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; @@ -8,19 +9,17 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableSetupAnalyzer - where TSyntaxKind : struct - where TMemberAccessExpressionSyntax : SyntaxNode - where TBlockStatementSyntax : SyntaxNode +internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableSetupAnalyzer { public override ImmutableArray SupportedDiagnostics { get; } - protected abstract TSyntaxKind InvocationExpressionKind { get; } + protected ImmutableArray IgnoredAncestorPaths { get; } = ImmutableArray.Create( + OperationKind.VariableDeclarator, + OperationKind.VariableDeclaration, + OperationKind.EventAssignment, + OperationKind.Argument); - protected abstract ImmutableArray IgnoredAncestorPaths { get; } - - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; private readonly ISubstitutionNodeFinder _substitutionNodeFinder; protected AbstractNonSubstitutableMemberReceivedInOrderAnalyzer( @@ -41,20 +40,12 @@ protected AbstractNonSubstitutableMemberReceivedInOrderAnalyzer( protected sealed override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - protected override Location GetSubstitutionNodeActualLocation( - in NonSubstitutableMemberAnalysisResult analysisResult) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - return analysisResult.Member.GetSubstitutionNodeActualLocation(analysisResult - .Symbol); - } - - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) - { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation - invocationOperation)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } @@ -65,70 +56,49 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) } foreach (var syntaxNode in _substitutionNodeFinder - .FindForReceivedInOrderExpression(syntaxNodeContext, invocationOperation) - .Where(node => ShouldAnalyzeNode(syntaxNodeContext.SemanticModel, node))) + .FindForReceivedInOrderExpression(operationAnalysisContext, invocationOperation) + .Where(operation => ShouldAnalyzeNode(operationAnalysisContext, operation))) { - var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntaxNode); - - if (symbolInfo.Symbol == null) - { - return; - } - - Analyze(syntaxNodeContext, syntaxNode, symbolInfo.Symbol); + Analyze(operationAnalysisContext, syntaxNode); } } - private bool ShouldAnalyzeNode(SemanticModel semanticModel, SyntaxNode syntaxNode) + private bool ShouldAnalyzeNode(OperationAnalysisContext operationAnalysisContext, IOperation operation) { - var maybeIgnoredExpression = FindIgnoredEnclosingExpression(syntaxNode); - if (maybeIgnoredExpression == null) + var maybeIgnoredOperation = FindIgnoredEnclosingOperation(operation); + if (maybeIgnoredOperation == null) { return true; } - if (syntaxNode.Parent is TMemberAccessExpressionSyntax || - semanticModel.GetOperation(syntaxNode.Parent) is IMemberReferenceOperation) - { - return false; - } - - var operation = semanticModel.GetOperation(maybeIgnoredExpression); - - if (syntaxNode.Parent is TMemberAccessExpressionSyntax || - semanticModel.GetOperation(syntaxNode.Parent) is IMemberReferenceOperation) - { - return false; - } - - if (operation is IArgumentOperation && - operation.Parent is IInvocationOperation invocationOperation && + if (maybeIgnoredOperation is IArgumentOperation && + maybeIgnoredOperation.Parent is IInvocationOperation invocationOperation && invocationOperation.TargetMethod.IsReceivedInOrderMethod()) { return true; } - if (operation.IsEventAssignmentOperation()) + if (maybeIgnoredOperation.IsEventAssignmentOperation()) { return false; } - var symbol = GetVariableDeclaratorSymbol(operation); + var symbol = GetVariableDeclaratorSymbol(maybeIgnoredOperation); if (symbol == null) { return false; } - var blockStatementSyntax = - maybeIgnoredExpression.Ancestors().OfType().FirstOrDefault(); + var blockOperation = maybeIgnoredOperation.Ancestors().OfType().FirstOrDefault(); - if (blockStatementSyntax == null) + if (blockOperation == null) { return false; } - var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(blockStatementSyntax); + var semanticModel = operationAnalysisContext.Compilation.GetSemanticModel(blockOperation.Syntax.SyntaxTree); + var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(blockOperation.Syntax); return !dataFlowAnalysis.ReadInside.Contains(symbol); } @@ -142,8 +112,6 @@ private static ILocalSymbol GetVariableDeclaratorSymbol(IOperation operation) }; } - private SyntaxNode FindIgnoredEnclosingExpression(SyntaxNode syntaxNode) - { - return syntaxNode.Ancestors().FirstOrDefault(ancestor => IgnoredAncestorPaths.Contains(ancestor.RawKind)); - } + private IOperation FindIgnoredEnclosingOperation(IOperation operation) => operation.Ancestors() + .FirstOrDefault(ancestor => IgnoredAncestorPaths.Contains(ancestor.Kind)); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs index 5a7151d9..de9f17f4 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -118,6 +118,14 @@ public SyntaxNode FindForAndDoesExpression( return FindForStandardExpression(parentInvocationExpression); } + public IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) + { + var visitor = new WhenVisitor(operationAnalysisContext, invocationOperation); + visitor.Visit(); + + return visitor.Operations; + } + public SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation) { var substituteOperation = invocationOperation.GetSubstituteOperation(); @@ -175,7 +183,7 @@ private class WhenVisitor : OperationWalker { private readonly OperationAnalysisContext _operationAnalysisContext; private readonly IInvocationOperation _whenInvocationOperation; - private readonly List _operations = new List(); + private readonly HashSet _operations = new HashSet(); private readonly IDictionary _semanticModelCache = new Dictionary(1); @@ -187,16 +195,13 @@ public WhenVisitor( _whenInvocationOperation = whenInvocationOperation; } - public IReadOnlyList Operations => _operations.AsReadOnly(); + public IEnumerable Operations => _operations; public void Visit() => Visit(_whenInvocationOperation); public override void VisitInvocation(IInvocationOperation operation) { - if (operation != _whenInvocationOperation) - { - _operations.Add(operation); - } + TryAdd(operation); base.VisitInvocation(operation); } @@ -218,10 +223,32 @@ public override void VisitMethodReference(IMethodReferenceOperation operation) public override void VisitPropertyReference(IPropertyReferenceOperation operation) { - _operations.Add(operation); + TryAdd(operation); base.VisitPropertyReference(operation); } + private void TryAdd(IOperation operation) + { + if (operation == _whenInvocationOperation) + { + return; + } + + if (operation.Parent == null) + { + _operations.Add(operation); + return; + } + + // For cases like Foo.Nested.Bar(); Foo.Nested().Bar + // we are only interested in last operation + // TODO make it smarter, will fail on multiple nested operations + if (_operations.Contains(operation.Parent) == false) + { + _operations.Add(operation); + } + } + private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) { var syntaxTree = syntaxNode.SyntaxTree; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 07f26db6..50b8284b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -15,6 +15,8 @@ internal interface ISubstitutionNodeFinder IEnumerable FindForReceivedInOrderExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol receivedInOrderInvocationSymbol = null); + IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); + SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation); IOperation FindOperationForStandardExpression(IInvocationOperation invocationOperation); diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 2fd9b399..7c9d7f16 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -122,6 +122,16 @@ public static ITypeSymbol GetTypeSymbol(this IAssignmentOperation assignmentOper return conversionTypeSymbol ?? assignmentOperation.Value.Type; } + public static IEnumerable Ancestors(this IOperation operation) + { + var parent = operation.Parent; + while (parent != null) + { + yield return parent; + parent = parent.Parent; + } + } + private static bool IsImplicitlyProvidedArrayWithoutValues(IArgumentOperation arg) { return arg.IsImplicit && diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs index 1344b621..44715522 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -2,13 +2,12 @@ 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 sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer +internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer { private static ImmutableArray IgnoredPaths { get; } = ImmutableArray.Create( (int)SyntaxKind.SimpleArgument, @@ -19,8 +18,4 @@ public NonSubstitutableMemberReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override ImmutableArray IgnoredAncestorPaths { get; } = IgnoredPaths; } \ No newline at end of file From 097150753a59dcf9c59009d102616c0d1186c5d5 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 10 Jul 2022 23:33:11 +0200 Subject: [PATCH 03/35] GH-153 - using operations api in ReceivedInReceivedInOrderAnalyzer --- Directory.Build.props | 2 +- .../NonSubstitutableMemberAnalyzer.cs | 1 - ...stitutableMemberReceivedInOrderAnalyzer.cs | 1 - .../ReceivedInReceivedInOrderAnalyzer.cs | 5 +-- ...stitutableMemberReceivedInOrderAnalyzer.cs | 1 - ...stractReceivedInReceivedInOrderAnalyzer.cs | 33 +++++++++---------- .../AbstractSubstitutionNodeFinder.cs | 32 ++++++++---------- .../ISubstitutionNodeFinder.cs | 4 +-- .../NonSubstitutableMemberAnalyzer.cs | 1 - .../ReceivedInReceivedInOrderAnalyzer.cs | 5 +-- ...eceivedInReceivedInOrderCodeFixVerifier.cs | 1 - ...eceivedInReceivedInOrderCodeFixVerifier.cs | 1 - 12 files changed, 33 insertions(+), 54 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 827d02ea..cb06957c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ - + true diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs index b59aa018..e92485a2 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs @@ -1,5 +1,4 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs index 4e4929b9..16c878b6 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -2,7 +2,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs index 75e3def5..926b7873 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs @@ -1,17 +1,14 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer +internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer { public ReceivedInReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, CSharp.DiagnosticDescriptorsProvider.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index a0930194..3202cec1 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs index b0bfd30b..f8fbceb4 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; @@ -7,11 +8,10 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractReceivedInReceivedInOrderAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct +internal abstract class AbstractReceivedInReceivedInOrderAnalyzer : AbstractDiagnosticAnalyzer { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; public override ImmutableArray SupportedDiagnostics { get; } @@ -25,16 +25,14 @@ protected AbstractReceivedInReceivedInOrderAnalyzer( SupportedDiagnostics = ImmutableArray.Create(diagnosticDescriptorsProvider.ReceivedUsedInReceivedInOrder); } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation invocationOperation)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } @@ -44,23 +42,22 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - foreach (var syntaxNode in _substitutionNodeFinder.FindForReceivedInOrderExpression( - syntaxNodeContext, - invocationOperation)) + foreach (var operation in _substitutionNodeFinder.FindForReceivedInOrderExpression( + operationAnalysisContext, + invocationOperation, + includeAll: true).OfType()) { - var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntaxNode); - - if (symbolInfo.Symbol.IsReceivedLikeMethod() == false) + if (operation.TargetMethod.IsReceivedLikeMethod() == false) { - continue; + continue; } var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.ReceivedUsedInReceivedInOrder, - syntaxNode.GetLocation(), - symbolInfo.Symbol.Name); + operation.Syntax.GetLocation(), + operation.TargetMethod.Name); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs index de9f17f4..25f5ccd5 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -118,9 +118,9 @@ public SyntaxNode FindForAndDoesExpression( return FindForStandardExpression(parentInvocationExpression); } - public IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) + public IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false) { - var visitor = new WhenVisitor(operationAnalysisContext, invocationOperation); + var visitor = new WhenVisitor(operationAnalysisContext, invocationOperation, includeAll); visitor.Visit(); return visitor.Operations; @@ -137,17 +137,6 @@ public IOperation FindOperationForStandardExpression(IInvocationOperation invoca return invocationOperation.GetSubstituteOperation(); } - public IEnumerable FindForReceivedInOrderExpression( - SyntaxNodeAnalysisContext syntaxNodeContext, - IInvocationOperation invocationOperation, - IMethodSymbol receivedInOrderInvocationSymbol = null) - { - var argumentOperation = invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument().First(); - - return FindInvocations(syntaxNodeContext, argumentOperation.Value.Syntax) - .Select(syntax => GetSubstitutionActualNode(syntaxNodeContext, syntax)); - } - protected abstract IEnumerable FindInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax); protected abstract SyntaxNode GetSubstitutionActualNode(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode); @@ -183,16 +172,19 @@ private class WhenVisitor : OperationWalker { private readonly OperationAnalysisContext _operationAnalysisContext; private readonly IInvocationOperation _whenInvocationOperation; - private readonly HashSet _operations = new HashSet(); - private readonly IDictionary - _semanticModelCache = new Dictionary(1); + private readonly bool _includeAll; + private readonly HashSet _operations = new (); + + private readonly Dictionary _semanticModelCache = new (1); public WhenVisitor( OperationAnalysisContext operationAnalysisContext, - IInvocationOperation whenInvocationOperation) + IInvocationOperation whenInvocationOperation, + bool includeAll = false) { _operationAnalysisContext = operationAnalysisContext; _whenInvocationOperation = whenInvocationOperation; + _includeAll = includeAll; } public IEnumerable Operations => _operations; @@ -243,7 +235,11 @@ private void TryAdd(IOperation operation) // For cases like Foo.Nested.Bar(); Foo.Nested().Bar // we are only interested in last operation // TODO make it smarter, will fail on multiple nested operations - if (_operations.Contains(operation.Parent) == false) + if (_includeAll) + { + _operations.Add(operation); + } + else if (_operations.Contains(operation.Parent) == false) { _operations.Add(operation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 50b8284b..4e5c2dfa 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -13,9 +13,7 @@ internal interface ISubstitutionNodeFinder IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); - IEnumerable FindForReceivedInOrderExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol receivedInOrderInvocationSymbol = null); - - IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); + IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false); SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation); diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs index c4ef7b41..725529d2 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalyzer.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs index bf687528..8f1b2091 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReceivedInReceivedInOrderAnalyzer.cs @@ -1,17 +1,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer +internal sealed class ReceivedInReceivedInOrderAnalyzer : AbstractReceivedInReceivedInOrderAnalyzer { public ReceivedInReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, VisualBasic.DiagnosticDescriptorsProvider.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs index 04ed86fe..97ad28c4 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs @@ -3,7 +3,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.CSharp.CodeFixProviders; using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; -using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.ReceivedInReceivedInOrderCodeFixProviderTests; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs index aa9a0baa..6c2214c2 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedInReceivedInOrderCodeFixVerifier.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; -using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; using NSubstitute.Analyzers.VisualBasic.CodeFixProviders; using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; From 98d4158664e30a7c83eee695597831dc2842c37a Mon Sep 17 00:00:00 2001 From: tpodolak Date: Mon, 11 Jul 2022 00:15:17 +0200 Subject: [PATCH 04/35] GH-153 - using operations api in UnusedReceivedAnalyzer --- .../UnusedReceivedAnalyzer.cs | 13 +---- .../AbstractNonSubstitutableMemberAnalysis.cs | 9 +-- .../AbstractNonSubstitutableSetupAnalyzer.cs | 55 +------------------ .../AbstractUnusedReceivedAnalyzer.cs | 45 +++++++-------- .../INonSubstitutableMemberAnalysis.cs | 5 -- .../UnusedReceivedAnalyzer.cs | 12 +--- 6 files changed, 30 insertions(+), 109 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs index 680bc820..f98fbd97 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs @@ -1,21 +1,12 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class UnusedReceivedAnalyzer : AbstractUnusedReceivedAnalyzer +internal sealed class UnusedReceivedAnalyzer : AbstractUnusedReceivedAnalyzer { - protected override ImmutableHashSet PossibleParentsRawKinds { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.SimpleMemberAccessExpression, - (int)SyntaxKind.InvocationExpression, - (int)SyntaxKind.ElementAccessExpression); - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public UnusedReceivedAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs index a6a4bb3e..c7c4c6a4 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs @@ -17,13 +17,6 @@ public NonSubstitutableMemberAnalysisResult Analyze( ISymbol symbol = null) => Analyze(accessedMember, symbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(accessedMember).Symbol); - public NonSubstitutableMemberAnalysisResult Analyze(IInvocationOperation invocationOperation, ISymbol symbol = null) - { - return Analyze( - invocationOperation.Syntax, - symbol ?? invocationOperation.TargetMethod); - } - public NonSubstitutableMemberAnalysisResult Analyze(IOperation operation) { var symbol = ExtractSymbol(operation); @@ -31,7 +24,7 @@ public NonSubstitutableMemberAnalysisResult Analyze(IOperation operation) return Analyze(operation.Syntax, symbol); } - protected virtual bool CanBeSubstituted( + private bool CanBeSubstituted( SyntaxNode accessedMember, ISymbol symbol) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs index 90f39e18..81199d90 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableSetupAnalyzer.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -22,27 +21,7 @@ protected AbstractNonSubstitutableSetupAnalyzer( _internalSetupSpecificationDescriptor = diagnosticDescriptorsProvider.InternalSetupSpecification; } - protected void Analyze(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, SyntaxNode syntaxNode, ISymbol symbol = null) - { - var analysisResult = _nonSubstitutableMemberAnalysis.Analyze(syntaxNodeAnalysisContext, syntaxNode, symbol); - - if (analysisResult.CanBeSubstituted == false) - { - ReportDiagnostics(syntaxNodeAnalysisContext, in analysisResult); - } - } - - protected void Analyze(OperationAnalysisContext operationAnalysisContext, IInvocationOperation operation, ISymbol symbol = null) - { - var analysisResult = _nonSubstitutableMemberAnalysis.Analyze(operation, symbol); - - if (analysisResult.CanBeSubstituted == false) - { - ReportDiagnostics(operationAnalysisContext, in analysisResult); - } - } - - protected void Analyze(OperationAnalysisContext operationAnalysisContext, IOperation operation, ISymbol symbol = null) + protected void Analyze(OperationAnalysisContext operationAnalysisContext, IOperation operation) { var analysisResult = _nonSubstitutableMemberAnalysis.Analyze(operation); @@ -52,41 +31,11 @@ protected void Analyze(OperationAnalysisContext operationAnalysisContext, IOpera } } - protected virtual Location GetSubstitutionNodeActualLocation(in NonSubstitutableMemberAnalysisResult analysisResult) - { - return analysisResult.Member.GetLocation(); - } - - private void ReportDiagnostics( - SyntaxNodeAnalysisContext context, - in NonSubstitutableMemberAnalysisResult analysisResult) - { - var location = GetSubstitutionNodeActualLocation(analysisResult); - if (analysisResult.NonVirtualMemberSubstitution) - { - var diagnostic = Diagnostic.Create( - NonVirtualSetupDescriptor, - location, - analysisResult.MemberName); - context.TryReportDiagnostic(diagnostic, analysisResult.Symbol); - } - - if (analysisResult.InternalMemberSubstitution) - { - var diagnostic = Diagnostic.Create( - _internalSetupSpecificationDescriptor, - location, - analysisResult.MemberName); - - context.ReportDiagnostic(diagnostic); - } - } - private void ReportDiagnostics( OperationAnalysisContext context, in NonSubstitutableMemberAnalysisResult analysisResult) { - var location = GetSubstitutionNodeActualLocation(analysisResult); + var location = analysisResult.Member.GetLocation(); if (analysisResult.NonVirtualMemberSubstitution) { var diagnostic = Diagnostic.Create( diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs index a6751026..c4d12b05 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs @@ -2,14 +2,14 @@ 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 AbstractUnusedReceivedAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct +internal abstract class AbstractUnusedReceivedAnalyzer : AbstractDiagnosticAnalyzer { - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; protected AbstractUnusedReceivedAnalyzer(IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) : base(diagnosticDescriptorsProvider) @@ -20,35 +20,36 @@ protected AbstractUnusedReceivedAnalyzer(IDiagnosticDescriptorsProvider diagnost public override ImmutableArray SupportedDiagnostics { get; } - protected abstract ImmutableHashSet PossibleParentsRawKinds { get; } - - protected abstract TSyntaxKind InvocationExpressionKind { get; } + private static readonly ImmutableHashSet PossibleParents = + ImmutableHashSet.Create(OperationKind.PropertyReference, OperationKind.Invocation); protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - var invocationExpression = syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { - return; + return; } - var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol; - - if (methodSymbol.IsReceivedLikeMethod() == false) + if (invocationOperation.TargetMethod.IsReceivedLikeMethod() == false) { return; } - var isConsideredAsUsed = IsConsideredAsUsed(invocationExpression); + if (IsConsideredAsUsed(invocationOperation)) + { + return; + } - if (isConsideredAsUsed) + // even though we have TargetMethod in IInvocationOperation, it wont tell us if method was called as extension + // or ordinary manner (and we need that information to correctly format diagnostic text) + if (operationAnalysisContext.Compilation + .GetSemanticModel(invocationOperation.Syntax.SyntaxTree) + .GetSymbolInfo(invocationOperation.Syntax).Symbol is not IMethodSymbol methodSymbol) { return; } @@ -59,15 +60,15 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) var diagnostic = Diagnostic.Create( diagnosticDescriptor, - invocationExpression.GetLocation(), + invocationOperation.Syntax.GetLocation(), methodSymbol.Name, methodSymbol.ContainingType.Name); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); } - private bool IsConsideredAsUsed(SyntaxNode receivedSyntaxNode) + private bool IsConsideredAsUsed(IOperation operation) { - return PossibleParentsRawKinds.Contains(receivedSyntaxNode.Parent.RawKind); + return operation.Parent != null && PossibleParents.Contains(operation.Parent.Kind); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs index 7225c7e7..24aeeed7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -11,9 +10,5 @@ NonSubstitutableMemberAnalysisResult Analyze( SyntaxNode accessedMember, ISymbol symbol = null); - NonSubstitutableMemberAnalysisResult Analyze( - IInvocationOperation invocationOperation, - ISymbol symbol = null); - NonSubstitutableMemberAnalysisResult Analyze(IOperation operation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs index 2f44ea26..99ab6d64 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/UnusedReceivedAnalyzer.cs @@ -1,20 +1,12 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class UnusedReceivedAnalyzer : AbstractUnusedReceivedAnalyzer +internal sealed class UnusedReceivedAnalyzer : AbstractUnusedReceivedAnalyzer { - protected override ImmutableHashSet PossibleParentsRawKinds { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.SimpleMemberAccessExpression, - (int)SyntaxKind.InvocationExpression); - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public UnusedReceivedAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance) { From 711bde4d5ec9d75ce0cb9d0680615377686753f7 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Mon, 11 Jul 2022 00:41:52 +0200 Subject: [PATCH 05/35] GH-153 - using operations api in SyncOverAsyncThrowsAnalyzer --- .../SyncOverAsyncThrowsAnalyzer.cs | 6 +- .../AbstractSyncOverAsyncThrowsAnalyzer.cs | 62 ++++++++----------- .../SyncOverAsyncThrowsAnalyzer.cs | 6 +- 3 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs index 363aa12a..b7985269 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs @@ -1,18 +1,14 @@ 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 SyncOverAsyncThrowsAnalyzer : AbstractSyncOverAsyncThrowsAnalyzer +internal sealed class SyncOverAsyncThrowsAnalyzer : AbstractSyncOverAsyncThrowsAnalyzer { public SyncOverAsyncThrowsAnalyzer() : base(CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind => SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs index bb35fc39..20db84d7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs @@ -7,14 +7,10 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSyncOverAsyncThrowsAnalyzer : AbstractDiagnosticAnalyzer - where TInvocationExpressionSyntax : SyntaxNode - where TSyntaxKind : struct +internal abstract class AbstractSyncOverAsyncThrowsAnalyzer : AbstractDiagnosticAnalyzer { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - private readonly Action _analyzeInvocationAction; - - protected abstract TSyntaxKind InvocationExpressionKind { get; } + private readonly Action _analyzeInvocationAction; protected AbstractSyncOverAsyncThrowsAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -23,7 +19,6 @@ protected AbstractSyncOverAsyncThrowsAnalyzer( { _substitutionNodeFinder = substitutionNodeFinder; SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.SyncOverAsyncThrows); - _analyzeInvocationAction = AnalyzeInvocation; } @@ -31,58 +26,51 @@ protected AbstractSyncOverAsyncThrowsAnalyzer( protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - var invocationExpression = syntaxNodeContext.Node; - if (!(syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression).Symbol is IMethodSymbol methodSymbol)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } - if (!methodSymbol.IsThrowSyncLikeMethod()) + if (invocationOperation.TargetMethod.IsThrowSyncLikeMethod() == false) { return; } - if (!(syntaxNodeContext.SemanticModel.GetOperation(invocationExpression) is IInvocationOperation invocationOperation)) + var substituteOperation = _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation); + + if (substituteOperation == null) { return; } - var substitutedExpression = _substitutionNodeFinder.FindForStandardExpression( - invocationOperation); + var returnType = GetReturnTypeSymbol(substituteOperation); - if (substitutedExpression == null) + if (IsTask(returnType, operationAnalysisContext.Compilation) == false) { return; } - var semanticModel = syntaxNodeContext.SemanticModel.GetSymbolInfo(substitutedExpression); - - ITypeSymbol returnType; - switch (semanticModel.Symbol) - { - case IMethodSymbol method: - returnType = method.ReturnType; - break; - case IPropertySymbol property: - returnType = property.Type; - break; - default: - returnType = null; - break; - } + operationAnalysisContext.ReportDiagnostic( + Diagnostic.Create( + DiagnosticDescriptorsProvider.SyncOverAsyncThrows, + invocationOperation.Syntax.GetLocation())); + } - if (!IsTask(returnType, syntaxNodeContext.Compilation)) + private static ITypeSymbol GetReturnTypeSymbol(IOperation substituteOperation) + { + var returnType = substituteOperation switch { - return; - } - - syntaxNodeContext.ReportDiagnostic( - Diagnostic.Create(DiagnosticDescriptorsProvider.SyncOverAsyncThrows, invocationExpression.GetLocation())); + IInvocationOperation substituteInvocationOperation => substituteInvocationOperation.TargetMethod.ReturnType, + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property.Type, + IConversionOperation conversionOperation => GetReturnTypeSymbol(conversionOperation.Operand), + _ => null + }; + return returnType; } private static bool IsTask(ITypeSymbol returnType, Compilation compilation) diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs index ab64ad4d..d120c765 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SyncOverAsyncThrowsAnalyzer.cs @@ -1,18 +1,14 @@ 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 sealed class SyncOverAsyncThrowsAnalyzer : AbstractSyncOverAsyncThrowsAnalyzer +internal sealed class SyncOverAsyncThrowsAnalyzer : AbstractSyncOverAsyncThrowsAnalyzer { public SyncOverAsyncThrowsAnalyzer() : base(VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind => SyntaxKind.InvocationExpression; } \ No newline at end of file From 409d1154f6b5f2d9b7159351e53f9c82990891f2 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Mon, 11 Jul 2022 01:09:18 +0200 Subject: [PATCH 06/35] GH-153 - using operations api in AsyncReceivedInOrderCallbackAnalyzer --- .../AsyncReceivedInOrderCallbackAnalyzer.cs | 17 +++------ ...actAsyncReceivedInOrderCallbackAnalyzer.cs | 35 +++++++------------ .../AsyncReceivedInOrderCallbackAnalyzer.cs | 26 +++++--------- 3 files changed, 24 insertions(+), 54 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs index 543b9f6a..61b04c15 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs @@ -2,31 +2,22 @@ using System.Linq; 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 AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer +internal sealed class AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer { public AsyncReceivedInOrderCallbackAnalyzer() : base(CSharp.DiagnosticDescriptorsProvider.Instance) { } - protected override int AsyncExpressionRawKind { get; } = (int)SyntaxKind.AsyncKeyword; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override IEnumerable GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList.Arguments.Select(arg => arg.Expression); - } - - protected override IEnumerable GetCallbackArgumentSyntaxTokens(SyntaxNode node) + protected override SyntaxToken? GetAsyncToken(SyntaxNode node) { - return node.ChildTokens().Select(token => token); + return node.ChildTokens().Select(token => token).FirstOrDefault(token => + token.Value.IsKind(SyntaxKind.AsyncKeyword)); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs index 06866190..8c15a4b5 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs @@ -4,15 +4,14 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractAsyncReceivedInOrderCallbackAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct - where TInvocationExpressionSyntax : SyntaxNode +internal abstract class AbstractAsyncReceivedInOrderCallbackAnalyzer : AbstractDiagnosticAnalyzer { - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; protected AbstractAsyncReceivedInOrderCallbackAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) @@ -24,38 +23,28 @@ protected AbstractAsyncReceivedInOrderCallbackAnalyzer( public override ImmutableArray SupportedDiagnostics { get; } - protected abstract int AsyncExpressionRawKind { get; } - - protected abstract TSyntaxKind InvocationExpressionKind { get; } - - protected abstract IEnumerable GetArgumentExpressions(TInvocationExpressionSyntax invocationExpressionSyntax); - - protected abstract IEnumerable GetCallbackArgumentSyntaxTokens(SyntaxNode node); + protected abstract SyntaxToken? GetAsyncToken(SyntaxNode node); protected sealed override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { - return; + return; } - if (methodSymbolInfo.Symbol.IsReceivedInOrderMethod() == false) + if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false) { return; } - foreach (var expression in GetArgumentExpressions(invocationExpression)) + foreach (var invocationOperationArgument in invocationOperation.Arguments) { - var asyncToken = GetCallbackArgumentSyntaxTokens(expression) - .FirstOrDefault(token => token.HasValue && token.Value.RawKind == AsyncExpressionRawKind); + var asyncToken = GetAsyncToken(invocationOperationArgument.Value.Syntax); if (asyncToken.HasValue == false) { @@ -66,7 +55,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) DiagnosticDescriptorsProvider.AsyncCallbackUsedInReceivedInOrder, asyncToken.Value.GetLocation()); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs index 850811b8..ef5a8188 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -9,30 +8,21 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer +internal sealed class AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer { public AsyncReceivedInOrderCallbackAnalyzer() : base(VisualBasic.DiagnosticDescriptorsProvider.Instance) { } - protected override int AsyncExpressionRawKind { get; } = (int)SyntaxKind.AsyncKeyword; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override IEnumerable GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList.Arguments.Select(arg => arg.GetExpression()); - } - - protected override IEnumerable GetCallbackArgumentSyntaxTokens(SyntaxNode node) + protected override SyntaxToken? GetAsyncToken(SyntaxNode node) { - switch (node) + return node switch { - case LambdaExpressionSyntax lambdaExpressionSyntax: - return lambdaExpressionSyntax.SubOrFunctionHeader.ChildTokens().Select(token => token); - } - - return Enumerable.Empty(); + LambdaExpressionSyntax lambdaExpressionSyntax => lambdaExpressionSyntax.SubOrFunctionHeader.ChildTokens() + .Select(token => token) + .FirstOrDefault(token => token.Value.IsKind(SyntaxKind.AsyncKeyword)), + _ => null + }; } } \ No newline at end of file From cb67c41a7133d796ab96e57e76bdb1f6d447cdba Mon Sep 17 00:00:00 2001 From: tpodolak Date: Wed, 13 Jul 2022 03:08:21 +0200 Subject: [PATCH 07/35] GH-153 - using operations api in ConflictingArgumentAssignmentsAnalyzer --- .../AsyncReceivedInOrderCallbackAnalyzer.cs | 1 - .../DiagnosticAnalyzers/CallInfoCallFinder.cs | 149 +----------------- .../ConflictingArgumentAssignmentsAnalyzer.cs | 4 +- .../AbstractCallInfoAnalyzer.cs | 2 +- .../AbstractCallInfoFinder.cs | 58 +++++-- ...tConflictingArgumentAssignmentsAnalyzer.cs | 49 ++---- .../DiagnosticAnalyzers/CallInfoContext.cs | 20 +++ .../DiagnosticAnalyzers/ICallInfoFinder.cs | 3 +- .../DiagnosticAnalyzers/CallInfoCallFinder.cs | 71 +-------- .../ConflictingArgumentAssignmentsAnalyzer.cs | 4 +- .../NonSubstitutableMemberAnalysis.cs | 4 +- ...stitutableMemberReceivedInOrderAnalyzer.cs | 7 - 12 files changed, 90 insertions(+), 282 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs index 61b04c15..6fd1566e 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs index 1a1e1a23..97e44d5f 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs @@ -1,159 +1,12 @@ -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.Shared; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class CallInfoCallFinder : AbstractCallInfoFinder { - public static CallInfoCallFinder Instance { get; } = new CallInfoCallFinder(); + public static CallInfoCallFinder Instance { get; } = new (); private CallInfoCallFinder() { } - - protected override CallInfoContext GetCallInfoContextInternal(SemanticModel semanticModel, SyntaxNode syntaxNode) - { - var visitor = new CallInfoVisitor(semanticModel); - visitor.Visit(syntaxNode); - - return new CallInfoContext( - argAtInvocations: visitor.ArgAtInvocations, - argInvocations: visitor.ArgInvocations, - indexerAccesses: visitor.DirectIndexerAccesses); - } - - private class CallInfoVisitor : CSharpSyntaxWalker - { - private readonly SemanticModel _semanticModel; - - public List ArgAtInvocations { get; } - - public List ArgInvocations { get; } - - public List DirectIndexerAccesses { get; } - - public CallInfoVisitor(SemanticModel semanticModel) - { - _semanticModel = semanticModel; - DirectIndexerAccesses = new List(); - ArgAtInvocations = new List(); - ArgInvocations = new List(); - } - - public override void VisitInvocationExpression(InvocationExpressionSyntax node) - { - var symbolInfo = _semanticModel.GetSymbolInfo(node); - - if (symbolInfo.Symbol != null && symbolInfo.Symbol.ContainingType.IsCallInfoSymbol()) - { - switch (symbolInfo.Symbol.Name) - { - case MetadataNames.CallInfoArgAtMethod: - ArgAtInvocations.Add(node); - break; - case MetadataNames.CallInfoArgMethod: - ArgInvocations.Add(node); - break; - } - } - - base.VisitInvocationExpression(node); - } - - public override void VisitElementAccessExpression(ElementAccessExpressionSyntax node) - { - var symbolInfo = ModelExtensions.GetSymbolInfo(_semanticModel, node).Symbol ?? ModelExtensions.GetSymbolInfo(_semanticModel, node.Expression).Symbol; - if (symbolInfo != null && symbolInfo.ContainingType.IsCallInfoSymbol()) - { - DirectIndexerAccesses.Add(node); - } - - base.VisitElementAccessExpression(node); - } - - public override void VisitClassDeclaration(ClassDeclarationSyntax node) - { - } - - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - } - - public override void VisitTrivia(SyntaxTrivia trivia) - { - } - - public override void VisitLeadingTrivia(SyntaxToken token) - { - } - - public override void VisitTrailingTrivia(SyntaxToken token) - { - } - - public override void VisitAttribute(AttributeSyntax node) - { - } - - public override void VisitAttributeArgument(AttributeArgumentSyntax node) - { - } - - public override void VisitAttributeArgumentList(AttributeArgumentListSyntax node) - { - } - - public override void VisitAttributeList(AttributeListSyntax node) - { - } - - public override void VisitAttributeTargetSpecifier(AttributeTargetSpecifierSyntax node) - { - } - - public override void VisitUsingStatement(UsingStatementSyntax node) - { - } - - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) - { - } - - public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) - { - } - - public override void VisitLiteralExpression(LiteralExpressionSyntax node) - { - } - - public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node) - { - } - - public override void VisitOmittedTypeArgument(OmittedTypeArgumentSyntax node) - { - } - - public override void VisitTypeArgumentList(TypeArgumentListSyntax node) - { - } - - public override void VisitTypeParameter(TypeParameterSyntax node) - { - } - - public override void VisitTypeParameterList(TypeParameterListSyntax node) - { - } - - public override void VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) - { - } - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index 0f462856..232a61c9 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -6,12 +6,10 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer +internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer { public ConflictingArgumentAssignmentsAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ 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 751af9e2..8799f7d8 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -120,7 +120,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument()) { var callInfoContext = - _callInfoFinder.GetCallInfoContext(syntaxNodeContext.SemanticModel, argumentExpressionSyntax); + _callInfoFinder.GetCallInfoContext(argumentExpressionSyntax); AnalyzeArgAtInvocations(syntaxNodeContext, callInfoContext, substituteCallParameters); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs index 8578d330..2bb7fd95 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs @@ -8,22 +8,17 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal abstract class AbstractCallInfoFinder : ICallInfoFinder { - public CallInfoContext GetCallInfoContext(SemanticModel semanticModel, IArgumentOperation argumentOperation) - { - var callContext = CallInfoContext.Empty; - foreach (var syntaxNode in argumentOperation.GetSyntaxes()) - { - var callInfoParameterSymbol = GetCallInfoParameterSymbol(semanticModel, syntaxNode); - var currentContext = GetCallInfoContextInternal(semanticModel, syntaxNode); - callContext = - callContext.Merge(CreateFilteredCallInfoContext(semanticModel, currentContext, callInfoParameterSymbol)); - } + public CallInfoContext GetCallInfoContext(IArgumentOperation argumentOperation) + { + var indexVisitor = new IndexerVisitor(); + indexVisitor.Visit(argumentOperation); - return callContext; + return new CallInfoContext( + indexVisitor.ArgAtInvocations, + indexVisitor.ArgInvocations, + indexVisitor.DirectIndexerAccesses); } - protected abstract CallInfoContext GetCallInfoContextInternal(SemanticModel semanticModel, SyntaxNode syntaxNode); - private static CallInfoContext CreateFilteredCallInfoContext( SemanticModel semanticModel, CallInfoContext callContext, @@ -99,4 +94,41 @@ private static IParameterSymbol GetCallInfoParameterSymbol(SemanticModel semanti return null; } + + private class IndexerVisitor : OperationWalker + { + public List ArgAtInvocations { get; } = new (); + + public List ArgInvocations { get; } = new (); + + public List DirectIndexerAccesses { get; } = new (); + + public override void VisitInvocation(IInvocationOperation operation) + { + if (operation.TargetMethod.ContainingType.IsCallInfoSymbol()) + { + switch (operation.TargetMethod.Name) + { + case MetadataNames.CallInfoArgAtMethod: + ArgAtInvocations.Add(operation); + break; + case MetadataNames.CallInfoArgMethod: + ArgInvocations.Add(operation); + break; + } + } + + base.VisitInvocation(operation); + } + + public override void VisitPropertyReference(IPropertyReferenceOperation operation) + { + if (operation.Property.ContainingType.IsCallInfoSymbol() && operation.Property.Parameters.Length > 0) + { + DirectIndexerAccesses.Add(operation); + } + + base.VisitPropertyReference(operation); + } + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index c5c139e5..22f42895 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -9,11 +9,10 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractConflictingArgumentAssignmentsAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct +internal abstract class AbstractConflictingArgumentAssignmentsAnalyzer : AbstractDiagnosticAnalyzer { private readonly ICallInfoFinder _callInfoFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; protected AbstractConflictingArgumentAssignmentsAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -27,17 +26,14 @@ protected AbstractConflictingArgumentAssignmentsAnalyzer( public override ImmutableArray SupportedDiagnostics { get; } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation - invocationOperation)) + if (syntaxNodeContext.Operation is not IInvocationOperation invocationOperation) { return; } @@ -47,58 +43,47 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) return; } - if (!(invocationOperation.GetSubstituteOperation() is IInvocationOperation substituteOperation)) + if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation substituteOperation) { return; } - var andDoesIndexers = FindCallInfoIndexers(syntaxNodeContext, invocationOperation).ToList(); + var andDoesIndexers = FindCallInfoIndexers(invocationOperation).ToList(); if (andDoesIndexers.Count == 0) { return; } - var previousCallIndexers = FindCallInfoIndexers(syntaxNodeContext, substituteOperation); + var previousCallIndexers = FindCallInfoIndexers(substituteOperation); var immutableHashSet = previousCallIndexers - .Select(indexerExpression => GetIndexerPosition(syntaxNodeContext, indexerExpression)).ToImmutableHashSet(); + .Select(indexerPropertyReferenceOperation => indexerPropertyReferenceOperation.GetIndexerPosition()) + .ToImmutableHashSet(); foreach (var indexerExpressionSyntax in andDoesIndexers) { - var position = GetIndexerPosition(syntaxNodeContext, indexerExpressionSyntax); + var position = indexerExpressionSyntax.GetIndexerPosition(); if (position.HasValue && immutableHashSet.Contains(position.Value)) { syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptorsProvider.ConflictingArgumentAssignments, - indexerExpressionSyntax.GetLocation())); + indexerExpressionSyntax.Syntax.GetLocation())); } } } - private int? GetIndexerPosition(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode indexerExpression) - { - return syntaxNodeContext.SemanticModel.GetOperation(indexerExpression).GetIndexerPosition(); - } - - private bool IsAssigned(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, SyntaxNode indexerExpressionSyntax) - { - return syntaxNodeAnalysisContext.SemanticModel.GetOperation(indexerExpressionSyntax) is - IPropertyReferenceOperation propertyReferenceOperation && - propertyReferenceOperation.Parent is ISimpleAssignmentOperation; - } - - private IEnumerable FindCallInfoIndexers(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation) + private IEnumerable FindCallInfoIndexers(IInvocationOperation invocationOperation) { // perf - dont use linq in hotpaths foreach (var argumentOperation in invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument()) { - foreach (var indexerExpressionSyntax in _callInfoFinder - .GetCallInfoContext(syntaxNodeContext.SemanticModel, argumentOperation).IndexerAccesses) + foreach (var propertyReference in _callInfoFinder + .GetCallInfoContext(argumentOperation).IndexerAccessesOperations) { - if (IsAssigned(syntaxNodeContext, indexerExpressionSyntax)) + if (propertyReference.Parent is ISimpleAssignmentOperation) { - yield return indexerExpressionSyntax; + yield return propertyReference; } } } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs index 519683c9..afc5b9a5 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -18,6 +19,12 @@ internal class CallInfoContext public IReadOnlyList ArgInvocations { get; } + public IReadOnlyList IndexerAccessesOperations { get; } + + public IReadOnlyList ArgAtInvocationsOperations { get; } + + public IReadOnlyList ArgInvocationsOperations { get; } + public CallInfoContext( IReadOnlyList argAtInvocations, IReadOnlyList argInvocations, @@ -26,6 +33,19 @@ public CallInfoContext( IndexerAccesses = indexerAccesses; ArgAtInvocations = argAtInvocations; ArgInvocations = argInvocations; + IndexerAccessesOperations = Array.Empty(); + ArgInvocationsOperations = Array.Empty(); + ArgAtInvocationsOperations = Array.Empty(); + } + + public CallInfoContext( + IReadOnlyList argAtInvocations, + IReadOnlyList argInvocations, + IReadOnlyList indexerAccesses) + { + IndexerAccessesOperations = indexerAccesses; + ArgAtInvocationsOperations = argAtInvocations; + ArgInvocationsOperations = argInvocations; } public CallInfoContext Merge(CallInfoContext callInfoContext) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ICallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ICallInfoFinder.cs index 86db72ef..feb4a9dd 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ICallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ICallInfoFinder.cs @@ -1,9 +1,8 @@ -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface ICallInfoFinder { - CallInfoContext GetCallInfoContext(SemanticModel semanticModel, IArgumentOperation argumentOperation); + CallInfoContext GetCallInfoContext(IArgumentOperation argumentOperation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs index 9caf3b5d..8ae44519 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs @@ -1,81 +1,12 @@ -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal class CallInfoCallFinder : AbstractCallInfoFinder { - public static CallInfoCallFinder Instance { get; } = new CallInfoCallFinder(); + public static CallInfoCallFinder Instance { get; } = new (); private CallInfoCallFinder() { } - - protected override CallInfoContext GetCallInfoContextInternal(SemanticModel semanticModel, SyntaxNode syntaxNode) - { - var visitor = new CallInfoVisitor(semanticModel); - visitor.Visit(syntaxNode); - - return new CallInfoContext( - argAtInvocations: visitor.ArgAtInvocations, - argInvocations: visitor.ArgInvocations, - indexerAccesses: visitor.DirectIndexerAccesses); - } - - private class CallInfoVisitor : VisualBasicSyntaxWalker - { - private readonly SemanticModel _semanticModel; - - public List ArgAtInvocations { get; } - - public List ArgInvocations { get; } - - public List DirectIndexerAccesses { get; } - - public CallInfoVisitor(SemanticModel semanticModel) - { - _semanticModel = semanticModel; - DirectIndexerAccesses = new List(); - ArgAtInvocations = new List(); - ArgInvocations = new List(); - } - - public override void VisitInvocationExpression(InvocationExpressionSyntax node) - { - var symbol = _semanticModel.GetSymbolInfo(node).Symbol; - - if (symbol != null && symbol.ContainingType.IsCallInfoSymbol()) - { - switch (symbol.Name) - { - case MetadataNames.CallInfoArgAtMethod: - ArgAtInvocations.Add(node); - break; - case MetadataNames.CallInfoArgMethod: - ArgInvocations.Add(node); - break; - case "Item": - DirectIndexerAccesses.Add(node); - break; - } - } - - if (symbol == null) - { - var expressionSymbol = _semanticModel.GetSymbolInfo(node.Expression).Symbol; - - if (expressionSymbol != null && expressionSymbol.ContainingType.IsCallInfoSymbol()) - { - DirectIndexerAccesses.Add(node); - } - } - - base.VisitInvocationExpression(node); - } - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index c111100a..1b4bb28c 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -6,12 +6,10 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer +internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer { public ConflictingArgumentAssignmentsAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs index 1c8533c4..c370ad9f 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs @@ -5,9 +5,9 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; -internal class NonSubstitutableMemberAnalysis : AbstractNonSubstitutableMemberAnalysis +internal sealed class NonSubstitutableMemberAnalysis : AbstractNonSubstitutableMemberAnalysis { - public static NonSubstitutableMemberAnalysis Instance { get; } = new NonSubstitutableMemberAnalysis(); + public static NonSubstitutableMemberAnalysis Instance { get; } = new (); private NonSubstitutableMemberAnalysis() { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs index 44715522..e5c33f3e 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -1,7 +1,5 @@ -using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; @@ -9,11 +7,6 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer { - private static ImmutableArray IgnoredPaths { get; } = ImmutableArray.Create( - (int)SyntaxKind.SimpleArgument, - (int)SyntaxKind.VariableDeclarator, - (int)SyntaxKind.AddAssignmentStatement); - public NonSubstitutableMemberReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance) { From 4b9adebbab41852fa7348b53322167b8816174e0 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Thu, 14 Jul 2022 00:22:25 +0200 Subject: [PATCH 08/35] GH-153 - using operations api in CallInfoAnalyzer --- .../Shared/AnalyzerBenchmark.cs | 24 +- .../DiagnosticAnalyzers/CallInfoAnalyzer.cs | 4 +- .../NonSubstitutableMemberAnalysis.cs | 2 +- .../ReEntrantCallFinder.cs | 6 +- .../SubstituteConstructorAnalysis.cs | 2 +- .../SubstituteConstructorMatcher.cs | 2 +- .../SubstituteProxyAnalysis.cs | 2 +- .../SubstitutionNodeFinder.cs | 61 +---- .../DiagnosticDescriptorsProvider.cs | 2 +- .../AbstractReEntrantSetupCodeFixProvider.cs | 8 +- ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 2 +- .../AbstractCallInfoAnalyzer.cs | 211 ++++++++---------- .../AbstractCallInfoFinder.cs | 92 ++++++-- ...tConflictingArgumentAssignmentsAnalyzer.cs | 2 +- .../AbstractNonSubstitutableMemberAnalyzer.cs | 2 +- .../AbstractReEntrantCallFinder.cs | 12 +- .../AbstractReEntrantSetupAnalyzer.cs | 6 +- .../AbstractSubstituteConstructorMatcher.cs | 2 +- .../AbstractSubstitutionNodeFinder.cs | 76 ++----- .../AbstractSyncOverAsyncThrowsAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/CallInfoContext.cs | 37 +-- .../ISubstitutionNodeFinder.cs | 8 +- .../DiagnosticDescriptors.cs | 3 +- .../Extensions/IOperationExtensions.cs | 2 + .../Extensions/TypeInfoExtensions.cs | 10 +- .../Settings/AnalyzersSettings.cs | 4 +- .../SharedResourceManager.cs | 2 +- .../TinyJson/JsonBuilder.cs | 2 +- .../TinyJson/JsonMapper.cs | 4 +- .../TinyJson/JsonParser.cs | 2 +- .../DiagnosticAnalyzers/CallInfoAnalyzer.cs | 4 +- .../ReEntrantCallFinder.cs | 6 +- .../SubstituteConstructorAnalysis.cs | 2 +- .../SubstituteConstructorMatcher.cs | 2 +- .../SubstituteProxyAnalysis.cs | 2 +- .../SubstitutionNodeFinder.cs | 106 +-------- .../DiagnosticDescriptorsProvider.cs | 2 +- .../CSharpProjectOptions.cs | 2 +- .../CSharpWorkspaceFactory.cs | 2 +- .../AnalyzerAdditionalText.cs | 2 +- .../Text/LinePositionInfo.cs | 2 +- .../Text/LinePositionSpanInfo.cs | 2 +- .../VisualBasicProjectOptions.cs | 2 +- .../VisualBasicWorkspaceFactory.cs | 2 +- 44 files changed, 256 insertions(+), 476 deletions(-) diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs index da866f12..c93e11e8 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs @@ -188,29 +188,29 @@ public void Run() [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] private class BenchmarkAnalyzer : DiagnosticAnalyzer { - internal List> SyntaxNodeActions { get; } = new List>(); + internal List> SyntaxNodeActions { get; } = new (); - internal List> CompilationStartActions { get; } = new List>(); + internal List> CompilationStartActions { get; } = new (); - internal List> CompilationEndActions { get; } = new List>(); + internal List> CompilationEndActions { get; } = new (); - internal List> CompilationActions { get; } = new List>(); + internal List> CompilationActions { get; } = new (); - internal List> SemanticModelActions { get; } = new List>(); + internal List> SemanticModelActions { get; } = new (); - internal List> SymbolActions { get; } = new List>(); + internal List> SymbolActions { get; } = new (); - internal List CodeBlockStartActions { get; } = new List(); + internal List CodeBlockStartActions { get; } = new (); - internal List> CodeBlockActions { get; } = new List>(); + internal List> CodeBlockActions { get; } = new (); - internal List> SyntaxTreeActions { get; } = new List>(); + internal List> SyntaxTreeActions { get; } = new (); - internal List> OperationActions { get; } = new List>(); + internal List> OperationActions { get; } = new (); - internal List> OperationBlockActions { get; } = new List>(); + internal List> OperationBlockActions { get; } = new (); - internal List> OperationBlockStartActions { get; } = new List>(); + internal List> OperationBlockStartActions { get; } = new (); private readonly DiagnosticAnalyzer _inner; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs index 6825b078..68838f00 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -6,15 +6,13 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer +internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer { public CallInfoAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance, SubstitutionNodeFinder.Instance) { } - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - protected override bool CanCast(Compilation compilation, ITypeSymbol sourceSymbol, ITypeSymbol destinationSymbol) { return compilation.ClassifyConversion(sourceSymbol, destinationSymbol).Exists; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs index 8fed48a5..4fff9cdc 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs @@ -7,7 +7,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class NonSubstitutableMemberAnalysis : AbstractNonSubstitutableMemberAnalysis { - public static NonSubstitutableMemberAnalysis Instance { get; } = new NonSubstitutableMemberAnalysis(); + public static NonSubstitutableMemberAnalysis Instance { get; } = new (); private NonSubstitutableMemberAnalysis() { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 091624f1..b32a55f8 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -10,7 +10,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class ReEntrantCallFinder : AbstractReEntrantCallFinder { - public static ReEntrantCallFinder Instance { get; } = new ReEntrantCallFinder(SubstitutionNodeFinder.Instance); + public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) : base(substitutionNodeFinder) @@ -55,8 +55,8 @@ private class ReEntrantCallVisitor : CSharpSyntaxWalker private readonly ReEntrantCallFinder _reEntrantCallFinder; private readonly Compilation _compilation; private readonly SemanticModel _semanticModel; - private readonly HashSet _visitedNodes = new HashSet(); - private readonly List _invocationSymbols = new List(); + private readonly HashSet _visitedNodes = new (); + private readonly List _invocationSymbols = new (); public ImmutableList InvocationSymbols => _invocationSymbols.ToImmutableList(); diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs index b1bc5ea6..570f6404 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class SubstituteConstructorAnalysis : AbstractSubstituteConstructorAnalysis { - public static SubstituteConstructorAnalysis Instance { get; } = new SubstituteConstructorAnalysis(); + public static SubstituteConstructorAnalysis Instance { get; } = new (); private SubstituteConstructorAnalysis() { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index 833e6369..1fab074f 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { - public static SubstituteConstructorMatcher Instance { get; } = new SubstituteConstructorMatcher(); + public static SubstituteConstructorMatcher Instance { get; } = new (); private SubstituteConstructorMatcher() { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs index 774bd903..57159266 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class SubstituteProxyAnalysis : AbstractSubstituteProxyAnalysis { - public static SubstituteProxyAnalysis Instance { get; } = new SubstituteProxyAnalysis(); + public static SubstituteProxyAnalysis Instance { get; } = new (); private SubstituteProxyAnalysis() { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 6d8e8279..9027e848 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -1,10 +1,3 @@ -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; @@ -14,61 +7,9 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; /// internal sealed class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder { - public static SubstitutionNodeFinder Instance { get; } = new SubstitutionNodeFinder(); + public static SubstitutionNodeFinder Instance { get; } = new (); private SubstitutionNodeFinder() { } - - protected override SyntaxNode GetSubstitutionActualNode(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode) - { - return syntaxNode.GetSubstitutionActualNode(node => syntaxNodeContext.SemanticModel.GetSymbolInfo(node).Symbol); - } - - // TODO replace with SyntaxVisitor or OperationVisitor - protected override IEnumerable FindInvocations(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 FindInvocations(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/DiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs index 99f704ac..1f4f07fd 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.CSharp; internal class DiagnosticDescriptorsProvider : AbstractDiagnosticDescriptorsProvider { - public static DiagnosticDescriptorsProvider Instance { get; } = new DiagnosticDescriptorsProvider(); + public static DiagnosticDescriptorsProvider Instance { get; } = new (); private DiagnosticDescriptorsProvider() { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs index 92029c80..7b1eeaa8 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs @@ -84,7 +84,7 @@ private async Task CreateChangedDocument( { if (IsArrayParamsArgument(semanticModel, argumentSyntax)) { - lambdaType = lambdaType ?? ConstructCallInfoLambdaType(methodSymbol, semanticModel); + lambdaType = lambdaType ?? ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); var updatedParamsArgumentSyntaxNode = CreateUpdatedParamsArgumentSyntaxNode( SyntaxGenerator.GetGenerator(context.Document), lambdaType, @@ -103,17 +103,17 @@ private async Task CreateChangedDocument( return await Simplifier.ReduceAsync(documentEditor.GetChangedDocument(), cancellationToken: ct); } - private static ITypeSymbol ConstructCallInfoLambdaType(IMethodSymbol methodSymbol, SemanticModel semanticModel) + private static ITypeSymbol ConstructCallInfoLambdaType(IMethodSymbol methodSymbol, Compilation compilation) { var callInfoOverloadMethodSymbol = methodSymbol.ContainingType.GetMembers(methodSymbol.Name) .Where(symbol => !symbol.Equals(methodSymbol.ConstructedFrom)) .OfType() - .First(method => method.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel))); + .First(method => method.Parameters.Any(param => param.Type.IsCallInfoDelegate(compilation))); var typeArgument = methodSymbol.TypeArguments.FirstOrDefault() ?? methodSymbol.ReceiverType; var constructedOverloadSymbol = callInfoOverloadMethodSymbol.Construct(typeArgument); var lambdaType = constructedOverloadSymbol.Parameters - .First(param => param.Type.IsCallInfoDelegate(semanticModel)).Type; + .First(param => param.Type.IsCallInfoDelegate(compilation)).Type; return lambdaType; } diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 0706f2ed..9ec94477 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -41,7 +41,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var methodSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(invocation).Symbol; var supportsThrowsAsync = SupportsThrowsAsync(semanticModel.Compilation); - if (!supportsThrowsAsync && methodSymbol.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel))) + if (!supportsThrowsAsync && methodSymbol.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel.Compilation))) { return; } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index 8799f7d8..be557b9c 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -9,12 +9,11 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractCallInfoAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct +internal abstract class AbstractCallInfoAnalyzer : AbstractDiagnosticAnalyzer { private readonly ICallInfoFinder _callInfoFinder; private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; protected AbstractCallInfoAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -39,45 +38,14 @@ protected AbstractCallInfoAnalyzer( protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected abstract bool CanCast(Compilation compilation, ITypeSymbol sourceSymbol, ITypeSymbol destinationSymbol); protected abstract bool IsAssignableTo(Compilation compilation, ITypeSymbol fromSymbol, ITypeSymbol toSymbol); - protected int? GetArgAtPosition(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, SyntaxNode invocationExpressionSyntax) - { - var operation = syntaxNodeAnalysisContext.SemanticModel.GetOperation(invocationExpressionSyntax); - - var literal = operation switch - { - IInvocationOperation invocationOperation => - invocationOperation.Arguments.First().Value as ILiteralOperation, - IArrayElementReferenceOperation arrayElementReferenceOperation => arrayElementReferenceOperation.Indices - .First() as ILiteralOperation, - IPropertyReferenceOperation propertyReferenceOperation => - propertyReferenceOperation.Arguments.First().Value as ILiteralOperation, - _ => null - }; - - if (literal == null || literal.ConstantValue.HasValue == false) - { - return null; - } - - return (int)literal.ConstantValue.Value; - } - - protected int? GetIndexerPosition(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, SyntaxNode indexerExpressionSyntax) - { - var operation = syntaxNodeAnalysisContext.SemanticModel.GetOperation(indexerExpressionSyntax); - return operation.GetIndexerPosition(); - } - - private bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation) + private bool SupportsCallInfo(Compilation compilation, IInvocationOperation invocationOperation) { if (invocationOperation.TargetMethod.IsCallInfoSupportingMethod() == false) { @@ -87,7 +55,7 @@ private bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, IInvo // perf - dont use linq in hotpath foreach (var arg in invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument()) { - if (arg.GetTypeSymbol().IsCallInfoDelegate(syntaxNodeContext.SemanticModel)) + if (arg.GetTypeSymbol().IsCallInfoDelegate(compilation)) { return true; } @@ -96,20 +64,19 @@ private bool SupportsCallInfo(SyntaxNodeAnalysisContext syntaxNodeContext, IInvo return false; } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (!(syntaxNodeContext.SemanticModel.GetOperation(syntaxNodeContext.Node) is IInvocationOperation - invocationOperation)) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { return; } - if (SupportsCallInfo(syntaxNodeContext, invocationOperation) == false) + if (SupportsCallInfo(operationAnalysisContext.Compilation, invocationOperation) == false) { return; } - var substituteCallParameters = GetSubstituteCallArgumentOperations(syntaxNodeContext, invocationOperation); + var substituteCallParameters = GetSubstituteCallArgumentOperations(operationAnalysisContext, invocationOperation); if (substituteCallParameters == null) { @@ -119,118 +86,114 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) foreach (var argumentExpressionSyntax in invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument()) { - var callInfoContext = - _callInfoFinder.GetCallInfoContext(argumentExpressionSyntax); + var callInfoContext = _callInfoFinder.GetCallInfoContext(argumentExpressionSyntax); - AnalyzeArgAtInvocations(syntaxNodeContext, callInfoContext, substituteCallParameters); + AnalyzeArgAtInvocations(operationAnalysisContext, callInfoContext, substituteCallParameters); - AnalyzeArgInvocations(syntaxNodeContext, callInfoContext, substituteCallParameters); + AnalyzeArgInvocations(operationAnalysisContext, callInfoContext, substituteCallParameters); - AnalyzeIndexerInvocations(syntaxNodeContext, callInfoContext, substituteCallParameters); + AnalyzeIndexerInvocations(operationAnalysisContext, callInfoContext, substituteCallParameters); } } - private void AnalyzeIndexerInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) + private void AnalyzeIndexerInvocations(OperationAnalysisContext operationAnalysisContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) { - foreach (var indexer in callInfoContext.IndexerAccesses) + foreach (var indexer in callInfoContext.IndexerAccessesOperations) { - var indexerInfo = GetIndexerInfo(syntaxNodeContext, indexer); + var indexerInfo = GetIndexerInfo(indexer); - var position = GetIndexerPosition(syntaxNodeContext, indexer); + var position = indexer.GetIndexerPosition(); - if (AnalyzeArgumentAccess(syntaxNodeContext, substituteCallParameters, indexer, position)) + if (AnalyzeArgumentAccess(operationAnalysisContext, substituteCallParameters, indexer, position)) { continue; } - if (AnalyzeCast(syntaxNodeContext, substituteCallParameters, indexer, in indexerInfo, position)) + if (AnalyzeCast(operationAnalysisContext, substituteCallParameters, indexer, in indexerInfo, position)) { continue; } - AnalyzeAssignment(syntaxNodeContext, substituteCallParameters, indexer, indexerInfo, position); + AnalyzeAssignment(operationAnalysisContext, substituteCallParameters, indexer, indexerInfo, position); } } - private void AnalyzeArgAtInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) + private void AnalyzeArgAtInvocations(OperationAnalysisContext operationAnalysisContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) { - foreach (var argAtInvocation in callInfoContext.ArgAtInvocations) + foreach (var argAtInvocation in callInfoContext.ArgAtInvocationsOperations) { - var position = GetArgAtPosition(syntaxNodeContext, argAtInvocation); + var position = argAtInvocation.GetIndexerPosition(); if (position.HasValue) { if (position.Value > substituteCallParameters.Count - 1) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoArgumentOutOfRange, - argAtInvocation.GetLocation(), + argAtInvocation.Syntax.GetLocation(), position); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); continue; } - var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(argAtInvocation); - if (symbolInfo.Symbol != null && - symbolInfo.Symbol is IMethodSymbol argAtMethodSymbol && - IsAssignableTo( - syntaxNodeContext.Compilation, + if (IsAssignableTo( + operationAnalysisContext.Compilation, substituteCallParameters[position.Value].GetTypeSymbol(), - argAtMethodSymbol.TypeArguments.First()) == false) + argAtInvocation.TargetMethod.TypeArguments.First()) == false) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoCouldNotConvertParameterAtPosition, - argAtInvocation.GetLocation(), + argAtInvocation.Syntax.GetLocation(), position, - argAtMethodSymbol.TypeArguments.First()); + argAtInvocation.TargetMethod.TypeArguments.First()); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); } } } } - private void AnalyzeArgInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) + private void AnalyzeArgInvocations(OperationAnalysisContext operationAnalysisContext, CallInfoContext callInfoContext, IReadOnlyList substituteCallParameters) { - foreach (var argInvocation in callInfoContext.ArgInvocations) + foreach (var argInvocationOperation in callInfoContext.ArgInvocationsOperations) { - var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(argInvocation); - if (symbolInfo.Symbol != null && symbolInfo.Symbol is IMethodSymbol argMethodSymbol) + var typeSymbol = argInvocationOperation.TargetMethod.TypeArguments.First(); + var parameterCount = + GetMatchingParametersCount(operationAnalysisContext.Compilation, substituteCallParameters, typeSymbol); + if (parameterCount == 0) { - var typeSymbol = argMethodSymbol.TypeArguments.First(); - var parameterCount = - GetMatchingParametersCount(syntaxNodeContext, substituteCallParameters, typeSymbol); - if (parameterCount == 0) - { - var diagnostic = Diagnostic.Create( - DiagnosticDescriptorsProvider.CallInfoCouldNotFindArgumentToThisCall, - argInvocation.GetLocation(), - typeSymbol); + var diagnostic = Diagnostic.Create( + DiagnosticDescriptorsProvider.CallInfoCouldNotFindArgumentToThisCall, + argInvocationOperation.Syntax.GetLocation(), + typeSymbol); - syntaxNodeContext.ReportDiagnostic(diagnostic); - continue; - } + operationAnalysisContext.ReportDiagnostic(diagnostic); + continue; + } - if (parameterCount > 1) - { - var diagnostic = Diagnostic.Create( - DiagnosticDescriptorsProvider.CallInfoMoreThanOneArgumentOfType, - argInvocation.GetLocation(), - typeSymbol); + if (parameterCount > 1) + { + var diagnostic = Diagnostic.Create( + DiagnosticDescriptorsProvider.CallInfoMoreThanOneArgumentOfType, + argInvocationOperation.Syntax.GetLocation(), + typeSymbol); - syntaxNodeContext.ReportDiagnostic(diagnostic); - } + operationAnalysisContext.ReportDiagnostic(diagnostic); } } } - private bool AnalyzeArgumentAccess(SyntaxNodeAnalysisContext syntaxNodeContext, IReadOnlyList substituteCallParameters, SyntaxNode indexer, int? position) + private bool AnalyzeArgumentAccess( + OperationAnalysisContext syntaxNodeContext, + IReadOnlyList substituteCallParameters, + IOperation indexerOperation, + int? position) { if (position.HasValue && position.Value > substituteCallParameters.Count - 1) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoArgumentOutOfRange, - indexer.GetLocation(), + indexerOperation.Syntax.GetLocation(), position.Value); syntaxNodeContext.ReportDiagnostic(diagnostic); @@ -240,27 +203,27 @@ private bool AnalyzeArgumentAccess(SyntaxNodeAnalysisContext syntaxNodeContext, return false; } - private bool AnalyzeCast(SyntaxNodeAnalysisContext syntaxNodeContext, IReadOnlyList substituteCallParameters, SyntaxNode indexer, in IndexerInfo indexerInfo, int? position) + private bool AnalyzeCast(OperationAnalysisContext operationAnalysisContext, IReadOnlyList substituteCallParameters, IOperation indexer, in IndexerInfo indexerInfo, int? position) { if (!position.HasValue || !indexerInfo.VerifyIndexerCast) { return false; } - if (!(syntaxNodeContext.SemanticModel.GetOperation(indexer).Parent is IConversionOperation conversionOperation)) + if (indexer.Parent is not IConversionOperation conversionOperation) { return false; } var type = conversionOperation.Type; - if (type != null && CanCast(syntaxNodeContext.Compilation, substituteCallParameters[position.Value].GetTypeSymbol(), type) == false) + if (type != null && CanCast(operationAnalysisContext.Compilation, substituteCallParameters[position.Value].GetTypeSymbol(), type) == false) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoCouldNotConvertParameterAtPosition, - indexer.GetLocation(), + indexer.Syntax.GetLocation(), position.Value, type); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); return true; } @@ -268,9 +231,9 @@ private bool AnalyzeCast(SyntaxNodeAnalysisContext syntaxNodeContext, IReadOnlyL } private bool AnalyzeAssignment( - SyntaxNodeAnalysisContext syntaxNodeContext, + OperationAnalysisContext operationAnalysisContext, IReadOnlyList substituteCallParameters, - SyntaxNode indexer, + IOperation indexerOperation, in IndexerInfo indexerInfo, int? position) { @@ -279,8 +242,7 @@ private bool AnalyzeAssignment( return false; } - if (syntaxNodeContext.SemanticModel.GetOperation(indexer) is IPropertyReferenceOperation referenceOperation && - referenceOperation.Parent is ISimpleAssignmentOperation simpleAssignmentOperation) + if (indexerOperation is IPropertyReferenceOperation { Parent: ISimpleAssignmentOperation simpleAssignmentOperation }) { var parameterSymbol = substituteCallParameters[position.Value]; if (parameterSymbol.Parameter.RefKind != RefKind.Out && @@ -288,25 +250,25 @@ private bool AnalyzeAssignment( { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoArgumentIsNotOutOrRef, - indexer.GetLocation(), + indexerOperation.Syntax.GetLocation(), position.Value, parameterSymbol.GetArgumentOperationDeclaredTypeSymbol()); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); return true; } var assignmentType = simpleAssignmentOperation.GetTypeSymbol(); var typeSymbol = substituteCallParameters[position.Value].GetArgumentOperationDeclaredTypeSymbol(); if (assignmentType != null && - IsAssignableTo(syntaxNodeContext.Compilation, assignmentType, typeSymbol) == false) + IsAssignableTo(operationAnalysisContext.Compilation, assignmentType, typeSymbol) == false) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.CallInfoArgumentSetWithIncompatibleValue, - indexer.GetLocation(), + indexerOperation.Syntax.GetLocation(), assignmentType, position.Value, typeSymbol); - syntaxNodeContext.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); return true; } } @@ -314,33 +276,34 @@ private bool AnalyzeAssignment( return false; } - private IReadOnlyList GetSubstituteCallArgumentOperations( - SyntaxNodeAnalysisContext syntaxNodeContext, - IInvocationOperation invocationOperation) + private IReadOnlyList GetSubstituteCallArgumentOperations(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) { - var parentMethodCallSyntax = - _substitutionNodeFinder.Find(syntaxNodeContext, invocationOperation).FirstOrDefault(); + var substituteOperation = _substitutionNodeFinder.Find(operationAnalysisContext, invocationOperation).FirstOrDefault(); - if (parentMethodCallSyntax == null) + if (substituteOperation == null) { return null; } - var operation = syntaxNodeContext.SemanticModel.GetOperation(parentMethodCallSyntax); - IEnumerable argumentOperations = operation switch + var argumentOperations = GetArgumentOperations(substituteOperation); + + return argumentOperations?.OrderBy(argOperation => argOperation.Parameter.Ordinal).ToList(); + } + + private static IEnumerable GetArgumentOperations(IOperation substituteOperation) + { + return substituteOperation switch { IInvocationOperation substituteMethodSymbol => substituteMethodSymbol.Arguments, IPropertyReferenceOperation propertySymbol => propertySymbol.Arguments, + IConversionOperation conversionOperation => GetArgumentOperations(conversionOperation.Operand), _ => null }; - - return argumentOperations?.OrderBy(argOperation => argOperation.Parameter.Ordinal).ToList(); } - private IndexerInfo GetIndexerInfo(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, SyntaxNode indexerExpressionSyntax) + private IndexerInfo GetIndexerInfo(IOperation indexerOperation) { - var operation = syntaxNodeAnalysisContext.SemanticModel.GetOperation(indexerExpressionSyntax); - ISymbol info = operation switch + ISymbol info = indexerOperation switch { IInvocationOperation inv => inv.TargetMethod, IArrayElementReferenceOperation x => x.Type, @@ -357,10 +320,10 @@ private IndexerInfo GetIndexerInfo(SyntaxNodeAnalysisContext syntaxNodeAnalysisC // See https://github.com/nsubstitute/NSubstitute/blob/26d0b0b880c623ef8cae8a0a71360ae2a9982f53/src/NSubstitute/Core/CallInfo.cs#L70 // for the logic behind it - private int GetMatchingParametersCount(SyntaxNodeAnalysisContext syntaxNodeContext, IReadOnlyList substituteCallParameters, ITypeSymbol typeSymbol) + private int GetMatchingParametersCount(Compilation compilation, IReadOnlyList substituteCallParameters, ITypeSymbol typeSymbol) { var declaringTypeMatchCount = - substituteCallParameters.Count(param => param.GetArgumentOperationDeclaredTypeSymbol() == typeSymbol); + substituteCallParameters.Count(param => param.GetArgumentOperationDeclaredTypeSymbol().Equals(typeSymbol)); if (declaringTypeMatchCount > 0) { @@ -368,7 +331,7 @@ private int GetMatchingParametersCount(SyntaxNodeAnalysisContext syntaxNodeConte } return substituteCallParameters.Count(param => - IsAssignableTo(syntaxNodeContext.Compilation, param.GetTypeSymbol(), typeSymbol)); + IsAssignableTo(compilation, param.GetTypeSymbol(), typeSymbol)); } private struct IndexerInfo diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs index 2bb7fd95..152b0026 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs @@ -10,40 +10,53 @@ internal abstract class AbstractCallInfoFinder : ICallInfoFinder { public CallInfoContext GetCallInfoContext(IArgumentOperation argumentOperation) { - var indexVisitor = new IndexerVisitor(); - indexVisitor.Visit(argumentOperation); + var callInfoContext = CallInfoContext.Empty; + foreach (var operation in GetCallInfoOperations(argumentOperation)) + { + var callInfoParameterSymbol = GetCallInfoParameterSymbol(operation); - return new CallInfoContext( - indexVisitor.ArgAtInvocations, - indexVisitor.ArgInvocations, - indexVisitor.DirectIndexerAccesses); + if (callInfoParameterSymbol == null) + { + continue; + } + + var indexVisitor = new CallInfoVisitor(); + indexVisitor.Visit(argumentOperation); + + var currentContext = new CallInfoContext( + indexVisitor.ArgAtInvocations, + indexVisitor.ArgInvocations, + indexVisitor.DirectIndexerAccesses); + + callInfoContext = + callInfoContext.Merge(CreateFilteredCallInfoContext(currentContext, callInfoParameterSymbol)); + } + + return callInfoContext; } private static CallInfoContext CreateFilteredCallInfoContext( - SemanticModel semanticModel, CallInfoContext callContext, IParameterSymbol callInfoParameterSymbol) { return new CallInfoContext( - argAtInvocations: GetMatchingNodes(semanticModel, callContext.ArgAtInvocations, callInfoParameterSymbol), - argInvocations: GetMatchingNodes(semanticModel, callContext.ArgInvocations, callInfoParameterSymbol), - indexerAccesses: GetMatchingNodes(semanticModel, callContext.IndexerAccesses, callInfoParameterSymbol)); + argAtInvocations: GetMatchingNodes(callContext.ArgAtInvocationsOperations, callInfoParameterSymbol), + argInvocations: GetMatchingNodes(callContext.ArgInvocationsOperations, callInfoParameterSymbol), + indexerAccesses: GetMatchingNodes(callContext.IndexerAccessesOperations, callInfoParameterSymbol)); } private static IReadOnlyList GetMatchingNodes( - SemanticModel semanticModel, IReadOnlyList nodes, - IParameterSymbol parameterSymbol) where T : SyntaxNode + IParameterSymbol parameterSymbol) where T : IOperation { - return nodes.Where(node => HasMatchingParameterReference(semanticModel, node, parameterSymbol)).ToList(); + return nodes.Where(node => HasMatchingParameterReference(node, parameterSymbol)).ToList(); } private static bool HasMatchingParameterReference( - SemanticModel semanticModel, - SyntaxNode syntaxNode, + IOperation operation, IParameterSymbol callInfoParameterSymbol) { - var parameterReferenceOperation = FindMatchingParameterReference(semanticModel, syntaxNode); + var parameterReferenceOperation = FindMatchingParameterReference(operation); return parameterReferenceOperation != null && parameterReferenceOperation.Parameter.Equals(callInfoParameterSymbol); @@ -85,23 +98,41 @@ private static IParameterReferenceOperation FindMatchingParameterReference(IOper return null; } - private static IParameterSymbol GetCallInfoParameterSymbol(SemanticModel semanticModel, SyntaxNode syntaxNode) + private static IEnumerable GetCallInfoOperations(IArgumentOperation argumentOperation) { - if (semanticModel.GetSymbolInfo(syntaxNode).Symbol is IMethodSymbol methodSymbol && methodSymbol.MethodKind != MethodKind.Constructor) + if (!argumentOperation.Parameter.IsParams) { - return methodSymbol.Parameters.FirstOrDefault(); + yield return argumentOperation.Value; + yield break; } - return null; + var initializerElementValues = + (argumentOperation.Value as IArrayCreationOperation)?.Initializer.ElementValues; + + foreach (var operation in initializerElementValues ?? Enumerable.Empty()) + { + yield return operation; + } } - private class IndexerVisitor : OperationWalker + private static IParameterSymbol GetCallInfoParameterSymbol(IOperation operation) + { + return operation switch + { + IInvocationOperation invocationOperation => invocationOperation.TargetMethod.Parameters.FirstOrDefault(), + IDelegateCreationOperation delegateCreationOperation => GetCallInfoParameterSymbol(delegateCreationOperation.Target), + IAnonymousFunctionOperation anonymousFunctionOperation => anonymousFunctionOperation.Symbol.Parameters.FirstOrDefault(), + _ => null + }; + } + + private class CallInfoVisitor : OperationWalker { public List ArgAtInvocations { get; } = new (); public List ArgInvocations { get; } = new (); - public List DirectIndexerAccesses { get; } = new (); + public List DirectIndexerAccesses { get; } = new (); public override void VisitInvocation(IInvocationOperation operation) { @@ -130,5 +161,22 @@ public override void VisitPropertyReference(IPropertyReferenceOperation operatio base.VisitPropertyReference(operation); } + + public override void VisitArrayElementReference(IArrayElementReferenceOperation operation) + { + ISymbol arrayReferenceSymbol = operation.ArrayReference switch + { + IInvocationOperation invocationOperation => invocationOperation.TargetMethod, + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, + _ => null + }; + + if (arrayReferenceSymbol != null && arrayReferenceSymbol.ContainingType.IsCallInfoSymbol()) + { + DirectIndexerAccesses.Add(operation); + } + + base.VisitArrayElementReference(operation); + } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index 22f42895..c0aa00a9 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -73,7 +73,7 @@ private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) } } - private IEnumerable FindCallInfoIndexers(IInvocationOperation invocationOperation) + private IEnumerable FindCallInfoIndexers(IInvocationOperation invocationOperation) { // perf - dont use linq in hotpaths foreach (var argumentOperation in invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument()) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs index 4a799133..0a1a4801 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs @@ -48,7 +48,7 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext return; } - AnalyzeMember(operationAnalysisContext, _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation)); + AnalyzeMember(operationAnalysisContext, _substitutionNodeFinder.FindForStandardExpression(invocationOperation)); } private void AnalyzeMember(OperationAnalysisContext operationAnalysisContext, IOperation accessedMember) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs index 82e2e491..d91a632a 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs @@ -22,7 +22,7 @@ public ImmutableList GetReEntrantCalls(Compilation compilation, Semanti { var symbolInfo = semanticModel.GetSymbolInfo(rootNode); - if (symbolInfo.Symbol.IsLocal() || semanticModel.GetTypeInfo(rootNode).IsCallInfoDelegate(semanticModel)) + if (symbolInfo.Symbol.IsLocal() || semanticModel.GetTypeInfo(rootNode).IsCallInfoDelegate(semanticModel.Compilation)) { return ImmutableList.Empty; } @@ -112,16 +112,18 @@ private IEnumerable GetOtherSubstitutionsForSymbol(SemanticModel semant var substitutedNode = _substitutionNodeFinder.FindForStandardExpression(operation); - var substituteNodeSymbol = semanticModel.GetSymbolInfo(substitutedNode).Symbol; - if (substituteNodeSymbol != rootNodeSymbol) + // TODO extract from operation + var substituteNodeSymbol = semanticModel.GetSymbolInfo(substitutedNode.Syntax).Symbol; + if (!substituteNodeSymbol.Equals(rootNodeSymbol)) { continue; } - var substituteNodeIdentifier = GetIdentifierExpressionSyntax(substitutedNode); + // TODO from operation + var substituteNodeIdentifier = GetIdentifierExpressionSyntax(substitutedNode.Syntax); var substituteIdentifierSymbol = semanticModel.GetSymbolInfo(substituteNodeIdentifier); - if (rootIdentifierSymbol.Symbol == substituteIdentifierSymbol.Symbol) + if (rootIdentifierSymbol.Symbol.Equals(substituteIdentifierSymbol.Symbol)) { yield return substituteNodeSymbol; } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index d3574f91..dd62109b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -66,7 +66,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) { var operation = syntaxNodeContext.SemanticModel.GetOperation(argument) as IArgumentOperation; - if (IsPassedByParamsArrayOfCallInfoFunc(syntaxNodeContext.SemanticModel, operation)) + if (IsPassedByParamsArrayOfCallInfoFunc(syntaxNodeContext.SemanticModel.Compilation, operation)) { continue; } @@ -129,11 +129,11 @@ private bool IsPassedByParamsArray(IArgumentOperation argumentOperation) argumentOperation.Parameter.Type is IArrayTypeSymbol; } - private bool IsPassedByParamsArrayOfCallInfoFunc(SemanticModel semanticModel, IArgumentOperation argumentOperation) + private bool IsPassedByParamsArrayOfCallInfoFunc(Compilation compilation, IArgumentOperation argumentOperation) { return IsPassedByParamsArray(argumentOperation) && argumentOperation.Parameter.Type is IArrayTypeSymbol arrayTypeSymbol && arrayTypeSymbol.ElementType is INamedTypeSymbol namedTypeSymbol && - namedTypeSymbol.IsCallInfoDelegate(semanticModel); + namedTypeSymbol.IsCallInfoDelegate(compilation); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs index 38245d2a..984a3588 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs @@ -21,7 +21,7 @@ internal abstract class AbstractSubstituteConstructorMatcher : ISubstituteConstr private static IReadOnlyDictionary> WellKnownSupportedConversions { get; } = new Dictionary> { - [SpecialType.System_Char] = new HashSet + [SpecialType.System_Char] = new () { SpecialType.System_Int16, SpecialType.System_Int32, diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs index 25f5ccd5..d30fc0ad 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -10,84 +10,53 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal abstract class AbstractSubstitutionNodeFinder : ISubstitutionNodeFinder { - public IEnumerable Find( - SyntaxNodeAnalysisContext syntaxNodeContext, - IInvocationOperation invocationOperation, - IMethodSymbol invocationExpressionSymbol = null) + public IEnumerable Find( + OperationAnalysisContext operationAnalysisContext, + IInvocationOperation invocationOperation) { if (invocationOperation == null) { - return Enumerable.Empty(); + return Enumerable.Empty(); } - var invocationExpression = invocationOperation.Syntax; - invocationExpressionSymbol ??= - syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; + var invocationExpressionSymbol = invocationOperation.TargetMethod; if (invocationExpressionSymbol == null || invocationExpressionSymbol.ContainingAssembly.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.Ordinal) == false) { - return Enumerable.Empty(); + return Enumerable.Empty(); } if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteDoMethod, StringComparison.Ordinal)) { var operation = invocationOperation.GetSubstituteOperation(); - return FindForWhenExpression(syntaxNodeContext, operation as IInvocationOperation); + return FindForWhenExpression(operationAnalysisContext, operation as IInvocationOperation); } if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenMethod, StringComparison.Ordinal) || invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenForAnyArgsMethod, StringComparison.Ordinal)) { - return FindForWhenExpression(syntaxNodeContext, invocationOperation, invocationExpressionSymbol); + return FindForWhenExpression(operationAnalysisContext, invocationOperation); } if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteAndDoesMethod, StringComparison.Ordinal)) { - var substitution = - FindForAndDoesExpression(syntaxNodeContext, invocationOperation, invocationExpressionSymbol); - return substitution != null ? new[] { substitution } : Enumerable.Empty(); + var substitution = FindForAndDoesExpression(operationAnalysisContext, invocationOperation); + return substitution != null ? new[] { substitution } : Enumerable.Empty(); } var standardSubstitution = FindForStandardExpression(invocationOperation); - return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); + return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); } - public IEnumerable FindForWhenExpression( - SyntaxNodeAnalysisContext syntaxNodeContext, - IInvocationOperation invocationOperation, - IMethodSymbol whenInvocationSymbol = null) + public IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) { if (invocationOperation == null) { yield break; } - var invocationExpression = invocationOperation.Syntax; - whenInvocationSymbol ??= - syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; - - if (whenInvocationSymbol == null) - { - yield break; - } - - var typeSymbol = whenInvocationSymbol.TypeArguments.FirstOrDefault() ?? whenInvocationSymbol.ReceiverType; - var argumentOperation = invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument().First(); - - foreach (var syntaxNode in FindInvocations(syntaxNodeContext, argumentOperation.Value.Syntax)) - { - var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntaxNode).Symbol; - if (symbol != null && typeSymbol != null && ContainsSymbol(typeSymbol, symbol)) - { - yield return GetSubstitutionActualNode(syntaxNodeContext, syntaxNode); - } - } - } - - public IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) - { var whenVisitor = new WhenVisitor(operationAnalysisContext, invocationOperation); whenVisitor.Visit(); @@ -105,17 +74,14 @@ public IEnumerable FindForWhenExpression(OperationAnalysisContext op } } - public SyntaxNode FindForAndDoesExpression( - SyntaxNodeAnalysisContext syntaxNodeContext, - IInvocationOperation invocationOperation, - IMethodSymbol invocationExpressionSymbol) + public IOperation FindForAndDoesExpression(OperationAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation) { - if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationExpression) + if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationOperation) { return null; } - return FindForStandardExpression(parentInvocationExpression); + return FindForStandardExpression(parentInvocationOperation); } public IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false) @@ -126,21 +92,11 @@ public IEnumerable FindForReceivedInOrderExpression(OperationAnalysi return visitor.Operations; } - public SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation) - { - var substituteOperation = invocationOperation.GetSubstituteOperation(); - return substituteOperation.Syntax; - } - - public IOperation FindOperationForStandardExpression(IInvocationOperation invocationOperation) + public IOperation FindForStandardExpression(IInvocationOperation invocationOperation) { return invocationOperation.GetSubstituteOperation(); } - protected abstract IEnumerable FindInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax); - - protected abstract SyntaxNode GetSubstitutionActualNode(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode); - private bool ContainsSymbol(ITypeSymbol containerSymbol, ISymbol symbol) { return GetBaseTypesAndThis(containerSymbol).Any(typeSymbol => typeSymbol.Equals(symbol.ContainingType)); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs index 20db84d7..586d3abf 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs @@ -41,7 +41,7 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext return; } - var substituteOperation = _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation); + var substituteOperation = _substitutionNodeFinder.FindForStandardExpression(invocationOperation); if (substituteOperation == null) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs index afc5b9a5..f910d133 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs @@ -8,40 +8,21 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class CallInfoContext { - public static CallInfoContext Empty { get; } = new CallInfoContext( - Array.Empty(), - Array.Empty(), - Array.Empty()); + public static CallInfoContext Empty { get; } = new ( + Array.Empty(), + Array.Empty(), + Array.Empty()); - public IReadOnlyList IndexerAccesses { get; } - - public IReadOnlyList ArgAtInvocations { get; } - - public IReadOnlyList ArgInvocations { get; } - - public IReadOnlyList IndexerAccessesOperations { get; } + public IReadOnlyList IndexerAccessesOperations { get; } public IReadOnlyList ArgAtInvocationsOperations { get; } public IReadOnlyList ArgInvocationsOperations { get; } - public CallInfoContext( - IReadOnlyList argAtInvocations, - IReadOnlyList argInvocations, - IReadOnlyList indexerAccesses) - { - IndexerAccesses = indexerAccesses; - ArgAtInvocations = argAtInvocations; - ArgInvocations = argInvocations; - IndexerAccessesOperations = Array.Empty(); - ArgInvocationsOperations = Array.Empty(); - ArgAtInvocationsOperations = Array.Empty(); - } - public CallInfoContext( IReadOnlyList argAtInvocations, IReadOnlyList argInvocations, - IReadOnlyList indexerAccesses) + IReadOnlyList indexerAccesses) { IndexerAccessesOperations = indexerAccesses; ArgAtInvocationsOperations = argAtInvocations; @@ -51,8 +32,8 @@ public CallInfoContext( public CallInfoContext Merge(CallInfoContext callInfoContext) { return new CallInfoContext( - ArgAtInvocations.Concat(callInfoContext.ArgAtInvocations).ToList(), - ArgInvocations.Concat(callInfoContext.ArgInvocations).ToList(), - IndexerAccesses.Concat(callInfoContext.IndexerAccesses).ToList()); + ArgAtInvocationsOperations.Concat(callInfoContext.ArgAtInvocationsOperations).ToList(), + ArgInvocationsOperations.Concat(callInfoContext.ArgInvocationsOperations).ToList(), + IndexerAccessesOperations.Concat(callInfoContext.IndexerAccessesOperations).ToList()); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 4e5c2dfa..04926a9d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -7,15 +7,11 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface ISubstitutionNodeFinder { - IEnumerable Find(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol invocationExpressionSymbol = null); - - IEnumerable FindForWhenExpression(SyntaxNodeAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation, IMethodSymbol whenInvocationSymbol = null); + IEnumerable Find(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false); - SyntaxNode FindForStandardExpression(IInvocationOperation invocationOperation); - - IOperation FindOperationForStandardExpression(IInvocationOperation invocationOperation); + IOperation FindForStandardExpression(IInvocationOperation invocationOperation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs index b05ae0bb..1968fe32 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs @@ -7,8 +7,7 @@ namespace NSubstitute.Analyzers.Shared; internal class DiagnosticDescriptors { - private static readonly ResourceManager SpecificResourceManager = - new ResourceManager( + private static readonly ResourceManager SpecificResourceManager = new ( $"{typeof(T).GetTypeInfo().Assembly.GetName().Name}.Resources", typeof(T).GetTypeInfo().Assembly); diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 7c9d7f16..0c32aca2 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -85,6 +85,8 @@ public static IEnumerable GetSyntaxes(this IArgumentOperation argume .First() as ILiteralOperation, IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Arguments.First().Value as ILiteralOperation, + IInvocationOperation invocationOperation => + invocationOperation.Arguments.First().Value as ILiteralOperation, _ => null }; diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs index fda14c2c..06e3b7d9 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs @@ -6,19 +6,19 @@ namespace NSubstitute.Analyzers.Shared.Extensions; internal static class TypeInfoExtensions { - public static bool IsCallInfoDelegate(this TypeInfo typeInfo, SemanticModel semanticModel) + public static bool IsCallInfoDelegate(this TypeInfo typeInfo, Compilation compilation) { var typeSymbol = typeInfo.Type ?? typeInfo.ConvertedType; - return typeSymbol.IsCallInfoDelegate(semanticModel); + return typeSymbol.IsCallInfoDelegate(compilation); } - public static bool IsCallInfoDelegate(this ITypeSymbol typeSymbol, SemanticModel semanticModel) + public static bool IsCallInfoDelegate(this ITypeSymbol typeSymbol, Compilation compilation) { var isCalledViaDelegate = typeSymbol != null && typeSymbol.TypeKind == TypeKind.Delegate && typeSymbol is INamedTypeSymbol namedTypeSymbol && - (namedTypeSymbol.ConstructedFrom.Equals(semanticModel.Compilation.GetTypeByMetadataName("System.Func`2")) || - namedTypeSymbol.ConstructedFrom.Equals(semanticModel.Compilation.GetTypeByMetadataName("System.Action`1"))) && + (namedTypeSymbol.ConstructedFrom.Equals(compilation.GetTypeByMetadataName("System.Func`2")) || + namedTypeSymbol.ConstructedFrom.Equals(compilation.GetTypeByMetadataName("System.Action`1"))) && IsCallInfoSymbol(namedTypeSymbol.TypeArguments.First()); return isCalledViaDelegate; diff --git a/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs b/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs index fb5c1f95..590e9b65 100644 --- a/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs +++ b/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Shared.Settings; internal class AnalyzersSettings { - public static AnalyzersSettings Default => new AnalyzersSettings(); + public static AnalyzersSettings Default => new (); public List Suppressions { get; set; } @@ -24,7 +24,7 @@ public static AnalyzersSettings CreateWithSuppressions(string target, string rul { return new AnalyzersSettings(new List { - new Suppression + new () { Target = target, Rules = new List diff --git a/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs b/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs index c82695bd..af4856e7 100644 --- a/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs +++ b/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Shared; internal class SharedResourceManager { - internal static ResourceManager Instance { get; } = new ResourceManager( + internal static ResourceManager Instance { get; } = new ( $"{typeof(SharedResourceManager).GetTypeInfo().Assembly.GetName().Name}.Resources", typeof(SharedResourceManager).GetTypeInfo().Assembly); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs index 67219333..80f0e537 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.TinyJson; [ExcludeFromCodeCoverage] internal class JsonBuilder { - private StringBuilder _builder = new StringBuilder(); + private StringBuilder _builder = new (); private bool _pretty = false; private int _level; diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs index 6c92773f..6a9a3337 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs @@ -14,8 +14,8 @@ internal static class JsonMapper { private static Encoder genericEncoder; private static Decoder genericDecoder; - private static Dictionary encoders = new Dictionary(); - private static Dictionary decoders = new Dictionary(); + private static Dictionary encoders = new (); + private static Dictionary decoders = new (); internal static Encoder GenericEncoder { get => genericEncoder; set => genericEncoder = value; } diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs index 649b00a5..8769a1da 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs @@ -27,7 +27,7 @@ private enum Token private StringReader _json; // temporary allocated - private StringBuilder _sb = new StringBuilder(); + private StringBuilder _sb = new (); public static object ParseValue(string jsonString) { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs index b4b9ec84..d9ca8eb5 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -6,15 +6,13 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer +internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer { public CallInfoAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance, SubstitutionNodeFinder.Instance) { } - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - protected override bool CanCast(Compilation compilation, ITypeSymbol sourceSymbol, ITypeSymbol destinationSymbol) { return compilation.ClassifyConversion(sourceSymbol, destinationSymbol).Exists; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 86842d2b..6107e044 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -10,7 +10,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal class ReEntrantCallFinder : AbstractReEntrantCallFinder { - public static ReEntrantCallFinder Instance { get; } = new ReEntrantCallFinder(SubstitutionNodeFinder.Instance); + public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) : base(substitutionNodeFinder) @@ -53,8 +53,8 @@ private class ReEntrantCallVisitor : VisualBasicSyntaxWalker private readonly ReEntrantCallFinder _reEntrantCallFinder; private readonly Compilation _compilation; private readonly SemanticModel _semanticModel; - private readonly HashSet _visitedNodes = new HashSet(); - private readonly List _invocationSymbols = new List(); + private readonly HashSet _visitedNodes = new (); + private readonly List _invocationSymbols = new (); public ImmutableList InvocationSymbols => _invocationSymbols.ToImmutableList(); diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs index 9a3eb1e4..d038206b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal class SubstituteConstructorAnalysis : AbstractSubstituteConstructorAnalysis { - public static SubstituteConstructorAnalysis Instance { get; } = new SubstituteConstructorAnalysis(); + public static SubstituteConstructorAnalysis Instance { get; } = new (); private SubstituteConstructorAnalysis() { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index 8c756b45..7e1c046f 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { - public static SubstituteConstructorMatcher Instance { get; } = new SubstituteConstructorMatcher(); + public static SubstituteConstructorMatcher Instance { get; } = new (); private SubstituteConstructorMatcher() { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs index 636e1e49..8d371281 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal sealed class SubstituteProxyAnalysis : AbstractSubstituteProxyAnalysis { - public static SubstituteProxyAnalysis Instance { get; } = new SubstituteProxyAnalysis(); + public static SubstituteProxyAnalysis Instance { get; } = new (); private SubstituteProxyAnalysis() { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 20361246..ba8cfdf0 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -1,116 +1,12 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -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 sealed class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder { - public static SubstitutionNodeFinder Instance { get; } = new SubstitutionNodeFinder(); + public static SubstitutionNodeFinder Instance { get; } = new (); private SubstitutionNodeFinder() { } - - // TODO replace with SyntaxVisitor or OperationVisitor - protected override IEnumerable FindInvocations(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) - { - SyntaxNode body = null; - switch (argumentSyntax) - { - case SingleLineLambdaExpressionSyntax _: - case ExpressionStatementSyntax _: - case LocalDeclarationStatementSyntax _: - case AssignmentStatementSyntax _: - body = argumentSyntax; - break; - case MultiLineLambdaExpressionSyntax simpleLambdaExpressionSyntax: - foreach (var syntaxNode in IterateStatements(simpleLambdaExpressionSyntax.Statements)) - { - yield return syntaxNode; - } - - break; - case MethodBlockSyntax methodBlockSyntax: - foreach (var syntaxNode in IterateStatements(methodBlockSyntax.Statements)) - { - yield return syntaxNode; - } - - break; - case UnaryExpressionSyntax unaryExpressionSyntax: - foreach (var syntaxNode in FindInvocations(syntaxNodeContext, unaryExpressionSyntax.Operand)) - { - yield return syntaxNode; - } - - break; - case IdentifierNameSyntax identifierNameSyntax: - var symbol = ModelExtensions.GetSymbolInfo(syntaxNodeContext.SemanticModel, identifierNameSyntax); - if (symbol.Symbol != null && symbol.Symbol.Locations.Any()) - { - var location = symbol.Symbol.Locations.First(); - var syntaxNode = location.SourceTree.GetRoot().FindNode(location.SourceSpan); - - SyntaxNode innerNode = null; - if (syntaxNode is MethodStatementSyntax methodStatementSyntax) - { - innerNode = methodStatementSyntax.Parent; - } - - innerNode ??= syntaxNode; - foreach (var expressionsForAnalysy in FindInvocations(syntaxNodeContext, innerNode)) - { - yield return expressionsForAnalysy; - } - } - - break; - } - - if (body == null) - { - yield break; - } - - var memberAccessExpressions = body.DescendantNodes() - .Where(node => node.IsKind(SyntaxKind.SimpleMemberAccessExpression)).ToList(); - var invocationExpressions = - body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.InvocationExpression)).ToList(); - - // rather ugly but prevents reporting two times the same thing - // as VB syntax is based on statements, you can't access body of method directly - if (invocationExpressions.Any()) - { - foreach (var invocationExpression in invocationExpressions) - { - yield return invocationExpression; - } - } - - if (memberAccessExpressions.Any()) - { - var descendants = new HashSet(invocationExpressions.SelectMany(x => x.DescendantNodes())); - foreach (var memberAccessExpression in memberAccessExpressions.Where(x => !descendants.Contains(x))) - { - yield return memberAccessExpression; - } - } - - IEnumerable IterateStatements(IEnumerable statements) - { - return statements.SelectMany(statement => FindInvocations(syntaxNodeContext, statement)); - } - } - - protected override SyntaxNode GetSubstitutionActualNode(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode) - { - return syntaxNode.GetSubstitutionActualNode(node => syntaxNodeContext.SemanticModel.GetSymbolInfo(node).Symbol); - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs index a69a6eca..b31611f9 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.VisualBasic; internal class DiagnosticDescriptorsProvider : AbstractDiagnosticDescriptorsProvider { - public static DiagnosticDescriptorsProvider Instance { get; } = new DiagnosticDescriptorsProvider(); + public static DiagnosticDescriptorsProvider Instance { get; } = new (); private DiagnosticDescriptorsProvider() { diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs index 7b63ae69..c328ceb8 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs @@ -7,7 +7,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp; public class CSharpProjectOptions : ProjectOptions { - public static CSharpProjectOptions Default { get; } = new CSharpProjectOptions( + public static CSharpProjectOptions Default { get; } = new ( RuntimeMetadataReference.Default, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs index 7a8db468..aa4aae01 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp; public class CSharpWorkspaceFactory : WorkspaceFactory { - public static CSharpWorkspaceFactory Default { get; } = new CSharpWorkspaceFactory(CSharpProjectOptions.Default); + public static CSharpWorkspaceFactory Default { get; } = new (CSharpProjectOptions.Default); protected override string DocumentExtension { get; } = "cs"; diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/AnalyzerAdditionalText.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/AnalyzerAdditionalText.cs index edd651ce..861e3abe 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/AnalyzerAdditionalText.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/AnalyzerAdditionalText.cs @@ -15,7 +15,7 @@ public AnalyzerAdditionalText(string fileName, string text) _text = text; } - public override SourceText GetText(CancellationToken cancellationToken = new CancellationToken()) + public override SourceText GetText(CancellationToken cancellationToken = default) { return SourceText.From(_text); } diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs index f37aabad..41a94c03 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs @@ -17,5 +17,5 @@ public LinePositionInfo(int index, int lineIndex, int columnIndex) public int ColumnIndex { get; } - public LinePosition LinePosition => new LinePosition(LineIndex, ColumnIndex); + public LinePosition LinePosition => new (LineIndex, ColumnIndex); } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs index 479cc253..87c276a7 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs @@ -16,5 +16,5 @@ public LinePositionSpanInfo(in LinePositionInfo start, in LinePositionInfo end) public TextSpan Span => TextSpan.FromBounds(Start.Index, End.Index); - public LinePositionSpan LineSpan => new LinePositionSpan(Start.LinePosition, End.LinePosition); + public LinePositionSpan LineSpan => new (Start.LinePosition, End.LinePosition); } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs index 1a58a984..e64a81eb 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic; public class VisualBasicProjectOptions : ProjectOptions { - public static VisualBasicProjectOptions Default { get; } = new VisualBasicProjectOptions( + public static VisualBasicProjectOptions Default { get; } = new ( RuntimeMetadataReference.Default.Add(MetadataReference.CreateFromFile(typeof(StandardModuleAttribute).Assembly.Location)), new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs index ed0a181e..85451de5 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic; public class VisualBasicWorkspaceFactory : WorkspaceFactory { - public static VisualBasicWorkspaceFactory Default { get; } = new VisualBasicWorkspaceFactory(VisualBasicProjectOptions.Default); + public static VisualBasicWorkspaceFactory Default { get; } = new (VisualBasicProjectOptions.Default); protected override string DocumentExtension { get; } = "vb"; From 8bd6f67bc39b15af8582dc18ebe677af542163ff Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 15 Jul 2022 03:39:25 +0200 Subject: [PATCH 09/35] GH-153 - using operations api in SubstituteAnalyzer --- .../CSharpDiagnosticAnalyzersBenchmarks.cs | 2 +- ...stituteForInternalMemberCodeFixProvider.cs | 4 +- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 4 +- .../SubstituteConstructorAnalysis.cs | 27 ---- .../SubstituteProxyAnalysis.cs | 27 ---- .../SubstitutionNodeFinder.cs | 15 --- ...stituteForInternalMemberCodeFixProvider.cs | 12 +- .../AbstractCallInfoAnalyzer.cs | 3 +- ...stitutableMemberReceivedInOrderAnalyzer.cs | 2 +- ...tractNonSubstitutableMemberWhenAnalyzer.cs | 8 +- ...stractReceivedInReceivedInOrderAnalyzer.cs | 8 +- .../AbstractSubstituteAnalyzer.cs | 125 ++++++++---------- .../AbstractSubstituteConstructorAnalysis.cs | 90 ++++++------- .../AbstractSubstituteConstructorMatcher.cs | 6 +- .../AbstractSubstituteProxyAnalysis.cs | 54 ++++---- .../AbstractSubstitutionNodeFinder.cs | 52 ++++---- .../ISubstituteConstructorAnalysis.cs | 4 +- .../ISubstituteConstructorMatcher.cs | 5 +- .../ISubstituteProxyAnalysis.cs | 11 +- .../ISubstitutionNodeFinder.cs | 6 +- .../DiagnosticAnalyzers/SubstituteContext.cs | 20 ++- ...stituteForInternalMemberCodeFixProvider.cs | 3 +- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 4 +- .../SubstituteConstructorAnalysis.cs | 28 ---- .../SubstituteProxyAnalysis.cs | 27 ---- .../SubstitutionNodeFinder.cs | 12 -- .../Extensions/SyntaxExtensions.cs | 26 ---- 27 files changed, 200 insertions(+), 385 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/Extensions/SyntaxExtensions.cs diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs index 252fe780..1117fd20 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs @@ -60,6 +60,6 @@ public CSharpDiagnosticAnalyzersBenchmarks() ReceivedInReceivedInOrderAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new ReceivedInReceivedInOrderAnalyzer()); AsyncReceivedInOrderCallbackAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new AsyncReceivedInOrderCallbackAnalyzer()); SyncOverAsyncThrowsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new SyncOverAsyncThrowsAnalyzer()); - WithAnyArgsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new WithAnyArgsArgumentMatcherAnalyzer()); + WithAnyArgsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new WithAnyArgsArgumentMatcherAnalyzer()); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index 5f0590ff..da455801 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -1,14 +1,14 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; using NSubstitute.Analyzers.CSharp.Refactorings; using NSubstitute.Analyzers.Shared.CodeFixProviders; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider +internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider { public SubstituteForInternalMemberCodeFixProvider() : base(SubstituteProxyAnalysis.Instance) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs index ba1420e1..0176e59f 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -9,15 +9,13 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer +internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer { public SubstituteAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstituteProxyAnalysis.Instance, SubstituteConstructorAnalysis.Instance, SubstituteConstructorMatcher.Instance) { } - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - protected override InvocationExpressionSyntax GetCorrespondingSubstituteInvocationExpressionSyntax(InvocationExpressionSyntax invocationExpressionSyntax, string substituteName) { var memberAccessExpressionSyntax = (MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs deleted file mode 100644 index 570f6404..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.CSharp.Extensions; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; - -internal class SubstituteConstructorAnalysis : AbstractSubstituteConstructorAnalysis -{ - public static SubstituteConstructorAnalysis Instance { get; } = new (); - - private SubstituteConstructorAnalysis() - { - } - - protected override IList GetInvocationArguments(InvocationExpressionSyntax invocationExpression) - { - return invocationExpression.ArgumentList?.Arguments.ToList(); - } - - protected override IList GetParameterExpressionsFromArrayArgument(ArgumentSyntax syntaxNode) - { - return syntaxNode.Expression.GetParameterExpressionsFromArrayArgument()?.Select(syntax => syntax).ToList(); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs deleted file mode 100644 index 57159266..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.CSharp.Extensions; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; - -internal class SubstituteProxyAnalysis : AbstractSubstituteProxyAnalysis -{ - public static SubstituteProxyAnalysis Instance { get; } = new (); - - private SubstituteProxyAnalysis() - { - } - - protected override IEnumerable GetTypeOfLikeExpressions(IList arrayParameters) - { - return arrayParameters.OfType(); - } - - protected override IEnumerable GetArrayInitializerArguments(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList?.Arguments.FirstOrDefault().Expression - .GetParameterExpressionsFromArrayArgument(); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs deleted file mode 100644 index 9027e848..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ /dev/null @@ -1,15 +0,0 @@ -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 sealed class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder -{ - public static SubstitutionNodeFinder Instance { get; } = new (); - - private SubstitutionNodeFinder() - { - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index f6d9f54f..f5bdf42a 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -3,20 +3,20 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractSubstituteForInternalMemberCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider +internal abstract class AbstractSubstituteForInternalMemberCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider where TInvocationExpressionSyntax : SyntaxNode - where TExpressionSyntax : SyntaxNode where TCompilationUnitSyntax : SyntaxNode { - private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; + private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SubstituteForInternalMember); - protected AbstractSubstituteForInternalMemberCodeFixProvider(ISubstituteProxyAnalysis substituteProxyAnalysis) + protected AbstractSubstituteForInternalMemberCodeFixProvider(ISubstituteProxyAnalysis substituteProxyAnalysis) { _substituteProxyAnalysis = substituteProxyAnalysis; } @@ -60,8 +60,8 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) private async Task GetDeclaringSyntaxReference(CodeFixContext context, TInvocationExpressionSyntax invocationExpression) { var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - var methodSymbol = semanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; - var actualProxyTypeSymbol = _substituteProxyAnalysis.GetActualProxyTypeSymbol(semanticModel, invocationExpression, methodSymbol); + var invocationOperation = semanticModel.GetOperation(invocationExpression) as IInvocationOperation; + var actualProxyTypeSymbol = _substituteProxyAnalysis.GetActualProxyTypeSymbol(invocationOperation); var syntaxReference = actualProxyTypeSymbol.DeclaringSyntaxReferences.FirstOrDefault(); return syntaxReference; } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index be557b9c..ca0ad98d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -278,7 +278,8 @@ private bool AnalyzeAssignment( private IReadOnlyList GetSubstituteCallArgumentOperations(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) { - var substituteOperation = _substitutionNodeFinder.Find(operationAnalysisContext, invocationOperation).FirstOrDefault(); + var substituteOperation = _substitutionNodeFinder + .Find(operationAnalysisContext.Compilation, invocationOperation).FirstOrDefault(); if (substituteOperation == null) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index 3202cec1..52d5ead1 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -55,7 +55,7 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext } foreach (var syntaxNode in _substitutionNodeFinder - .FindForReceivedInOrderExpression(operationAnalysisContext, invocationOperation) + .FindForReceivedInOrderExpression(operationAnalysisContext.Compilation, invocationOperation) .Where(operation => ShouldAnalyzeNode(operationAnalysisContext, operation))) { Analyze(operationAnalysisContext, syntaxNode); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs index 79d45970..2301b16b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs @@ -36,9 +36,9 @@ protected override void InitializeAnalyzer(AnalysisContext context) context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) + private void AnalyzeInvocation(OperationAnalysisContext context) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) + if (context.Operation is not IInvocationOperation invocationOperation) { return; } @@ -48,10 +48,10 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext return; } - var operations = _substitutionNodeFinder.FindForWhenExpression(operationAnalysisContext, invocationOperation); + var operations = _substitutionNodeFinder.FindForWhenExpression(context.Compilation, invocationOperation); foreach (var operation in operations) { - Analyze(operationAnalysisContext, operation); + Analyze(context, operation); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs index f8fbceb4..1f479626 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs @@ -30,9 +30,9 @@ protected override void InitializeAnalyzer(AnalysisContext context) context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) + private void AnalyzeInvocation(OperationAnalysisContext context) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) + if (context.Operation is not IInvocationOperation invocationOperation) { return; } @@ -43,7 +43,7 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext } foreach (var operation in _substitutionNodeFinder.FindForReceivedInOrderExpression( - operationAnalysisContext, + context.Compilation, invocationOperation, includeAll: true).OfType()) { @@ -57,7 +57,7 @@ private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext operation.Syntax.GetLocation(), operation.TargetMethod.Name); - operationAnalysisContext.ReportDiagnostic(diagnostic); + context.ReportDiagnostic(diagnostic); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs index 65778d95..1b4a0118 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs @@ -3,26 +3,23 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSubstituteAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct - where TInvocationExpressionSyntax : SyntaxNode - where TExpressionSyntax : SyntaxNode - where TArgumentSyntax : SyntaxNode +internal abstract class AbstractSubstituteAnalyzer : AbstractDiagnosticAnalyzer where TInvocationExpressionSyntax : SyntaxNode { - private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; - private readonly ISubstituteConstructorAnalysis _substituteConstructorAnalysis; + private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; + private readonly ISubstituteConstructorAnalysis _substituteConstructorAnalysis; private readonly ISubstituteConstructorMatcher _substituteConstructorMatcher; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; protected AbstractSubstituteAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, - ISubstituteProxyAnalysis substituteProxyAnalysis, - ISubstituteConstructorAnalysis substituteConstructorAnalysis, + ISubstituteProxyAnalysis substituteProxyAnalysis, + ISubstituteConstructorAnalysis substituteConstructorAnalysis, ISubstituteConstructorMatcher substituteConstructorMatcher) : base(diagnosticDescriptorsProvider) { @@ -47,35 +44,26 @@ protected AbstractSubstituteAnalyzer( public override ImmutableArray SupportedDiagnostics { get; } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) + if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) { - return; + return; } - var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol; - if (methodSymbol == null || methodSymbol.MethodKind != MethodKind.Ordinary) - { - return; - } + var methodSymbol = invocationOperation.TargetMethod; if (methodSymbol.IsSubstituteCreateLikeMethod() == false) { return; } - var substituteContext = new SubstituteContext(syntaxNodeContext, invocationExpression, methodSymbol); + var substituteContext = new SubstituteContext(operationAnalysisContext, invocationOperation); if (methodSymbol.Name.Equals(MetadataNames.NSubstituteForMethod, StringComparison.Ordinal) || methodSymbol.Name.Equals(MetadataNames.SubstituteFactoryCreate, StringComparison.Ordinal)) @@ -91,14 +79,14 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) } } - private void AnalyzeSubstitute(SubstituteContext substituteContext) + private void AnalyzeSubstitute(SubstituteContext substituteContext) { if (AnalyzeProxies(substituteContext)) { return; } - var proxyType = _substituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext); + var proxyType = _substituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext.InvocationOperation); if (proxyType == null) { @@ -114,14 +102,14 @@ private void AnalyzeSubstitute(SubstituteContext su AnalyzeConstructor(substituteContext, constructorContext); } - private void AnalyzePartialSubstitute(SubstituteContext substituteContext) + private void AnalyzePartialSubstitute(SubstituteContext substituteContext) { if (AnalyzeProxies(substituteContext)) { return; } - var proxyType = _substituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext); + var proxyType = _substituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext.InvocationOperation); if (proxyType == null) { @@ -147,7 +135,7 @@ private void AnalyzePartialSubstitute(SubstituteContext substituteContext, ConstructorContext constructorContext) + private void AnalyzeConstructor(SubstituteContext substituteContext, ConstructorContext constructorContext) { if (AnalyzeConstructorAccessibility(substituteContext, constructorContext)) { @@ -159,30 +147,27 @@ private void AnalyzeConstructor(SubstituteContext s return; } - if (AnalyzeConstructorInvocation(substituteContext, constructorContext)) - { - return; - } + AnalyzeConstructorInvocation(substituteContext, constructorContext); } - private bool AnalyzeProxies(SubstituteContext substituteContext) + private bool AnalyzeProxies(SubstituteContext substituteContext) { - var proxies = _substituteProxyAnalysis.GetProxySymbols(substituteContext).ToList(); + var proxies = _substituteProxyAnalysis.GetProxySymbols(substituteContext.InvocationOperation).ToList(); var classProxies = proxies.Where(proxy => proxy.TypeKind == TypeKind.Class).Distinct(); if (classProxies.Count() > 1) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteMultipleClasses, - substituteContext.InvocationExpression.GetLocation()); + substituteContext.InvocationOperation.Syntax.GetLocation()); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; } return false; } - private bool AnalyzeConstructorParametersCount(SubstituteContext substituteContext, ConstructorContext constructorContext) + private bool AnalyzeConstructorParametersCount(SubstituteContext substituteContext, ConstructorContext constructorContext) { var invocationArgumentTypes = constructorContext.InvocationParameters?.Length; switch (constructorContext.ConstructorType.TypeKind) @@ -190,20 +175,20 @@ private bool AnalyzeConstructorParametersCount(SubstituteContext 0: var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForInterface, - substituteContext.InvocationExpression.GetLocation(), - GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationExpression, substituteContext.MethodSymbol)); + substituteContext.InvocationOperation.Syntax.GetLocation(), + GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod)); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; case TypeKind.Interface: return false; case TypeKind.Delegate when invocationArgumentTypes > 0: var delegateDiagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForDelegate, - substituteContext.InvocationExpression.GetLocation(), - GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationExpression, substituteContext.MethodSymbol)); + substituteContext.InvocationOperation.Syntax.GetLocation(), + GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod)); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(delegateDiagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(delegateDiagnostic); return true; case TypeKind.Delegate: return false; @@ -211,53 +196,53 @@ private bool AnalyzeConstructorParametersCount(SubstituteContext substituteContext, ITypeSymbol proxyType) + private bool AnalyzeTypeKind(SubstituteContext substituteContext, ITypeSymbol proxyType) { if (proxyType.TypeKind == TypeKind.Interface || proxyType.TypeKind == TypeKind.Delegate) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.PartialSubstituteForUnsupportedType, - substituteContext.InvocationExpression.GetLocation(), - GetCorrespondingSubstituteMethod(substituteContext.InvocationExpression, substituteContext.MethodSymbol), - substituteContext.InvocationExpression.ToString()); + substituteContext.InvocationOperation.Syntax.GetLocation(), + GetCorrespondingSubstituteMethod(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod), + substituteContext.InvocationOperation.Syntax); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; } return false; } - private bool AnalyzeTypeAccessability(SubstituteContext substituteContext, ITypeSymbol proxyType) + private bool AnalyzeTypeAccessability(SubstituteContext substituteContext, ITypeSymbol proxyType) { if (proxyType.DeclaredAccessibility == Accessibility.Internal && proxyType.InternalsVisibleToProxyGenerator() == false) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteForInternalMember, - substituteContext.InvocationExpression.GetLocation()); + substituteContext.InvocationOperation.Syntax.GetLocation()); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; } return false; } - private bool AnalyzeConstructorInvocation(SubstituteContext substituteContext, ConstructorContext constructorContext) + private bool AnalyzeConstructorInvocation(SubstituteContext substituteContext, ConstructorContext constructorContext) { if (constructorContext.ConstructorType.TypeKind != TypeKind.Class || constructorContext.InvocationParameters == null || constructorContext.PossibleConstructors == null) { @@ -266,40 +251,43 @@ private bool AnalyzeConstructorInvocation(SubstituteContext _substituteConstructorMatcher.MatchesInvocation( - substituteContext.SyntaxNodeAnalysisContext.SemanticModel.Compilation, ctor, constructorContext.InvocationParameters) == + substituteContext.OperationAnalysisContext.Compilation, ctor, constructorContext.InvocationParameters) == false)) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteConstructorMismatch, - substituteContext.InvocationExpression.GetLocation(), - substituteContext.MethodSymbol.ToMinimalMethodString(substituteContext.SyntaxNodeAnalysisContext.SemanticModel), + substituteContext.InvocationOperation.Syntax.GetLocation(), + substituteContext.InvocationOperation.TargetMethod.ToMinimalMethodString( + substituteContext.OperationAnalysisContext.Compilation.GetSemanticModel(substituteContext + .InvocationOperation.Syntax.SyntaxTree)), constructorContext.ConstructorType.ToString()); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; } return false; } - private bool AnalyzeConstructorAccessibility(SubstituteContext substituteContext, ConstructorContext constructorContext) + private bool AnalyzeConstructorAccessibility(SubstituteContext substituteContext, ConstructorContext constructorContext) { if (constructorContext.ConstructorType.TypeKind == TypeKind.Class && constructorContext.AccessibleConstructors != null && constructorContext.AccessibleConstructors.Any() == false) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteForWithoutAccessibleConstructor, - substituteContext.InvocationExpression.GetLocation(), + substituteContext.InvocationOperation.Syntax.GetLocation(), constructorContext.ConstructorType.ToString()); - substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic); + substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; } return false; } - private string GetCorrespondingSubstituteMethod(TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + private string GetCorrespondingSubstituteMethod(SyntaxNode syntaxNode, IMethodSymbol methodSymbol) { + var invocationExpressionSyntax = (TInvocationExpressionSyntax)syntaxNode; switch (methodSymbol.Name) { case MetadataNames.SubstituteFactoryCreatePartial: @@ -311,8 +299,9 @@ private string GetCorrespondingSubstituteMethod(TInvocationExpressionSyntax invo } } - private string GetSubstituteMethodWithoutConstructorArguments(TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + private string GetSubstituteMethodWithoutConstructorArguments(SyntaxNode invocationExpressionSyntax, IMethodSymbol methodSymbol) { - return GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(invocationExpressionSyntax, methodSymbol).ToString(); + return GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments( + (TInvocationExpressionSyntax)invocationExpressionSyntax, methodSymbol).ToString(); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs index 3890a90c..de6dd48c 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs @@ -2,21 +2,22 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSubstituteConstructorAnalysis : ISubstituteConstructorAnalysis where TInvocationExpression : SyntaxNode - where TArgumentSyntax : SyntaxNode +internal class SubstituteConstructorAnalysis : ISubstituteConstructorAnalysis { - public ConstructorContext CollectConstructorContext(SubstituteContext substituteContext, ITypeSymbol proxyTypeSymbol) + public static SubstituteConstructorAnalysis Instance { get; } = new (); + + public ConstructorContext CollectConstructorContext(SubstituteContext substituteContext, ITypeSymbol proxyTypeSymbol) { if (proxyTypeSymbol.Kind == SymbolKind.TypeParameter) { return new ConstructorContext(proxyTypeSymbol, null, null, null); } - var accessibleConstructors = GetAccessibleConstructors(proxyTypeSymbol); var invocationParameterTypes = GetInvocationInfo(substituteContext); bool IsPossibleConstructor(IMethodSymbol methodSymbol) @@ -31,6 +32,7 @@ bool IsPossibleConstructor(IMethodSymbol methodSymbol) return invocationParameterTypes.Length >= nonParamsParametersCount; } + var accessibleConstructors = GetAccessibleConstructors(proxyTypeSymbol); var possibleConstructors = invocationParameterTypes != null && accessibleConstructors != null ? accessibleConstructors.Where(IsPossibleConstructor) .ToArray() @@ -43,76 +45,49 @@ bool IsPossibleConstructor(IMethodSymbol methodSymbol) invocationParameterTypes); } - protected abstract IList GetInvocationArguments(TInvocationExpression invocationExpression); - - protected abstract IList GetParameterExpressionsFromArrayArgument(TArgumentSyntax syntaxNode); - - private ITypeSymbol[] GetInvocationInfo(SubstituteContext substituteContext) + private ITypeSymbol[] GetInvocationInfo(SubstituteContext substituteContext) { - var infos = substituteContext.MethodSymbol.IsGenericMethod + var infos = substituteContext.InvocationOperation.TargetMethod.IsGenericMethod ? GetGenericInvocationArgumentTypes(substituteContext) : GetNonGenericInvocationArgumentTypes(substituteContext); return infos; } - private ITypeSymbol[] GetGenericInvocationArgumentTypes(SubstituteContext substituteContext) + private ITypeSymbol[] GetGenericInvocationArgumentTypes(SubstituteContext substituteContext) { - var arguments = GetInvocationArguments(substituteContext.InvocationExpression); + var arguments = substituteContext.InvocationOperation.Arguments; - if (arguments == null) - { - return null; - } - - if (arguments.Count == 0) + if (arguments.Length == 0) { return Array.Empty(); } - var typeInfos = arguments.Select(arg => GetTypeInfo(substituteContext, arg.DescendantNodes().First())) - .ToList(); - - var possibleParamsArgument = typeInfos.First(); - // if passing array of objects as a sole element - if (arguments.Count == 1 && - possibleParamsArgument.ConvertedType is IArrayTypeSymbol arrayTypeSymbol && - arrayTypeSymbol.ElementType.Equals(substituteContext.SyntaxNodeAnalysisContext.Compilation.ObjectType)) + if (arguments.Length == 1 && arguments.Single().Value is IArrayCreationOperation arrayTypeSymbol) { - return GetArgumentTypeInfo(substituteContext, arguments.First()); + return TypeSymbols(arrayTypeSymbol); } - return typeInfos.Select(type => type.Type).ToArray(); + return arguments.SelectMany(ArgType).ToArray(); } - private ITypeSymbol[] GetNonGenericInvocationArgumentTypes(SubstituteContext substituteContext) + private ITypeSymbol[] GetNonGenericInvocationArgumentTypes(SubstituteContext substituteContext) { // Substitute.For(new [] { typeof(T) }, new object[] { 1, 2, 3}) // actual arguments reside in second arg - var arrayArgument = GetInvocationArguments(substituteContext.InvocationExpression)?.Skip(1).FirstOrDefault(); + var arrayArgument = GetInvocationArguments(substituteContext).Skip(1).FirstOrDefault(); if (arrayArgument == null) { return null; } - return GetArgumentTypeInfo(substituteContext, arrayArgument); - } - - private ITypeSymbol[] GetArgumentTypeInfo(SubstituteContext substituteContext, TArgumentSyntax arrayArgument) - { - // new object[] { }; // means we dont pass any arguments - var parameterExpressionsFromArrayArgument = GetParameterExpressionsFromArrayArgument(arrayArgument); - if (parameterExpressionsFromArrayArgument == null) + // if passing array of objects as a sole element + if (arrayArgument.Value is IArrayCreationOperation arrayTypeSymbol) { - return null; + return TypeSymbols(arrayTypeSymbol); } - // new object[] { 1, 2, 3}); // means we pass arguments - var types = parameterExpressionsFromArrayArgument - .Select(exp => GetTypeInfo(substituteContext, exp).Type) - .ToArray(); - - return types; + return ArgType(arrayArgument); } private IMethodSymbol[] GetAccessibleConstructors(ITypeSymbol genericArgument) @@ -142,8 +117,29 @@ bool IsVisibleToProxy(IMethodSymbol symbol) (IsAccessible(symbol) || IsVisibleToProxy(symbol))).ToArray(); } - private TypeInfo GetTypeInfo(SubstituteContext substituteContext, SyntaxNode syntax) + private IEnumerable GetInvocationArguments(SubstituteContext substituteContext) + { + return substituteContext.InvocationOperation.GetOrderedArgumentOperations(); + } + + private ITypeSymbol[] TypeSymbols(IArrayCreationOperation arrayInitializerOperation) + { + return arrayInitializerOperation.Initializer.ElementValues.Select(item => + item is IConversionOperation conversionOperation + ? conversionOperation.Operand.Type + : item.Type) + .ToArray(); + } + + private ITypeSymbol[] ArgType(IArgumentOperation x) { - return substituteContext.SyntaxNodeAnalysisContext.SemanticModel.GetTypeInfo(syntax); + if (x.ArgumentKind == ArgumentKind.ParamArray) + { + var arrayInitializerOperation = x.Value as IArrayCreationOperation; + + return TypeSymbols(arrayInitializerOperation); + } + + return Array.Empty(); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs index 984a3588..753ac5db 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs @@ -33,7 +33,7 @@ internal abstract class AbstractSubstituteConstructorMatcher : ISubstituteConstr } }; - public bool MatchesInvocation(Compilation compilation, IMethodSymbol methodSymbol, IList invocationParameters) + public bool MatchesInvocation(Compilation compilation, IMethodSymbol methodSymbol, IReadOnlyList invocationParameters) { if (methodSymbol.Parameters.Length == 0) { @@ -47,7 +47,7 @@ public bool MatchesInvocation(Compilation compilation, IMethodSymbol methodSymbo protected abstract bool IsConvertible(Compilation compilation, ITypeSymbol source, ITypeSymbol destination); // TODO simplify once https://github.com/nsubstitute/NSubstitute.Analyzers/issues/153 is implemented - private bool MatchesInvocation(Compilation compilation, IParameterSymbol symbol, IList invocationParameters) + private bool MatchesInvocation(Compilation compilation, IParameterSymbol symbol, IReadOnlyList invocationParameters) { if (!symbol.IsParams) { @@ -66,7 +66,7 @@ private bool MatchesInvocation(Compilation compilation, IParameterSymbol symbol, } return invocationParameters - .Where((typeSymbol, index) => index >= symbol.Ordinal).All(invocationSymbol => + .Where((_, index) => index >= symbol.Ordinal).All(invocationSymbol => ClassifyConversion(compilation, invocationSymbol, arrayTypeSymbol.ElementType)); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs index e0e9ffc0..7291eb07 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs @@ -1,59 +1,53 @@ -using System.Collections.Generic; -using System.Collections.Immutable; +using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSubstituteProxyAnalysis : - ISubstituteProxyAnalysis - where TInvocationExpressionSyntax : SyntaxNode where TExpressionSyntax : SyntaxNode +internal class SubstituteProxyAnalysis : ISubstituteProxyAnalysis { - public ITypeSymbol GetActualProxyTypeSymbol(SubstituteContext substituteContext) - { - return GetActualProxyTypeSymbol(substituteContext.SyntaxNodeAnalysisContext.SemanticModel, substituteContext.InvocationExpression, substituteContext.MethodSymbol); - } - - public ImmutableArray GetProxySymbols(SubstituteContext substituteContext) - { - return GetProxySymbols(substituteContext.SyntaxNodeAnalysisContext.SemanticModel, substituteContext.InvocationExpression, substituteContext.MethodSymbol); - } + public static SubstituteProxyAnalysis Instance { get; } = new (); - public ITypeSymbol GetActualProxyTypeSymbol(SemanticModel semanticModel, TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + public ITypeSymbol GetActualProxyTypeSymbol(IInvocationOperation invocationOperation) { - var proxies = GetProxySymbols(semanticModel, invocationExpressionSyntax, methodSymbol).ToList(); + var proxies = GetProxySymbols(invocationOperation).ToList(); var classSymbol = proxies.FirstOrDefault(symbol => symbol.TypeKind == TypeKind.Class); return classSymbol ?? proxies.FirstOrDefault(); } - public ImmutableArray GetProxySymbols(SemanticModel semanticModel, TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + public ImmutableArray GetProxySymbols(IInvocationOperation invocationOperation) { - if (methodSymbol.IsGenericMethod) + if (invocationOperation.TargetMethod.IsGenericMethod) { - return methodSymbol.TypeArguments; + return invocationOperation.TargetMethod.TypeArguments; } - var arrayParameters = GetArrayInitializerArguments(invocationExpressionSyntax)?.ToList(); + var arrayParameters = GetArrayInitializerArguments(invocationOperation); if (arrayParameters == null) { return ImmutableArray.Empty; } - var proxyTypes = GetTypeOfLikeExpressions(arrayParameters) - .Select(exp => - semanticModel - .GetTypeInfo(exp.DescendantNodes().First())) - .Where(model => model.Type != null) - .Select(model => model.Type) + var proxyTypes = arrayParameters.ElementValues.OfType() + .Select(typeOfOperation => typeOfOperation.TypeOperand) .ToImmutableArray(); - return arrayParameters.Count == proxyTypes.Length ? proxyTypes : ImmutableArray.Empty; + // get typeof like expressions + return arrayParameters.ElementValues.Length == proxyTypes.Length + ? proxyTypes + : ImmutableArray.Empty; } - protected abstract IEnumerable GetTypeOfLikeExpressions(IList arrayParameters); - - protected abstract IEnumerable GetArrayInitializerArguments(TInvocationExpressionSyntax invocationExpressionSyntax); + private IArrayInitializerOperation GetArrayInitializerArguments(IInvocationOperation invocationOperation) + { + return invocationOperation.Arguments.FirstOrDefault()?.Value switch + { + IArrayCreationOperation operation => operation.Initializer, + _ => null + }; + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs index d30fc0ad..0c09b9ac 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs @@ -2,16 +2,17 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSubstitutionNodeFinder : ISubstitutionNodeFinder +internal class SubstitutionNodeFinder : ISubstitutionNodeFinder { + public static SubstitutionNodeFinder Instance { get; } = new (); + public IEnumerable Find( - OperationAnalysisContext operationAnalysisContext, + Compilation compilation, IInvocationOperation invocationOperation) { if (invocationOperation == null) @@ -30,18 +31,18 @@ public IEnumerable Find( if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteDoMethod, StringComparison.Ordinal)) { var operation = invocationOperation.GetSubstituteOperation(); - return FindForWhenExpression(operationAnalysisContext, operation as IInvocationOperation); + return FindForWhenExpression(compilation, operation as IInvocationOperation); } if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenMethod, StringComparison.Ordinal) || invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteWhenForAnyArgsMethod, StringComparison.Ordinal)) { - return FindForWhenExpression(operationAnalysisContext, invocationOperation); + return FindForWhenExpression(compilation, invocationOperation); } if (invocationExpressionSymbol.Name.Equals(MetadataNames.NSubstituteAndDoesMethod, StringComparison.Ordinal)) { - var substitution = FindForAndDoesExpression(operationAnalysisContext, invocationOperation); + var substitution = FindForAndDoesExpression(invocationOperation); return substitution != null ? new[] { substitution } : Enumerable.Empty(); } @@ -50,14 +51,14 @@ public IEnumerable Find( return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); } - public IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) + public IEnumerable FindForWhenExpression(Compilation compilation, IInvocationOperation invocationOperation) { if (invocationOperation == null) { yield break; } - var whenVisitor = new WhenVisitor(operationAnalysisContext, invocationOperation); + var whenVisitor = new WhenVisitor(compilation, invocationOperation); whenVisitor.Visit(); var typeSymbol = invocationOperation.TargetMethod.TypeArguments.FirstOrDefault() ?? @@ -74,19 +75,12 @@ public IEnumerable FindForWhenExpression(OperationAnalysisContext op } } - public IOperation FindForAndDoesExpression(OperationAnalysisContext syntaxNodeContext, IInvocationOperation invocationOperation) - { - if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationOperation) - { - return null; - } - - return FindForStandardExpression(parentInvocationOperation); - } - - public IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false) + public IEnumerable FindForReceivedInOrderExpression( + Compilation compilation, + IInvocationOperation invocationOperation, + bool includeAll = false) { - var visitor = new WhenVisitor(operationAnalysisContext, invocationOperation, includeAll); + var visitor = new WhenVisitor(compilation, invocationOperation, includeAll); visitor.Visit(); return visitor.Operations; @@ -124,9 +118,19 @@ private static ISymbol ExtractSymbol(IOperation operation) return symbol; } + private IOperation FindForAndDoesExpression(IInvocationOperation invocationOperation) + { + if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationOperation) + { + return null; + } + + return FindForStandardExpression(parentInvocationOperation); + } + private class WhenVisitor : OperationWalker { - private readonly OperationAnalysisContext _operationAnalysisContext; + private readonly Compilation _compilation; private readonly IInvocationOperation _whenInvocationOperation; private readonly bool _includeAll; private readonly HashSet _operations = new (); @@ -134,11 +138,11 @@ private class WhenVisitor : OperationWalker private readonly Dictionary _semanticModelCache = new (1); public WhenVisitor( - OperationAnalysisContext operationAnalysisContext, + Compilation compilation, IInvocationOperation whenInvocationOperation, bool includeAll = false) { - _operationAnalysisContext = operationAnalysisContext; + _compilation = compilation; _whenInvocationOperation = whenInvocationOperation; _includeAll = includeAll; } @@ -209,7 +213,7 @@ private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) return semanticModel; } - semanticModel = _operationAnalysisContext.Compilation.GetSemanticModel(syntaxTree); + semanticModel = _compilation.GetSemanticModel(syntaxTree); _semanticModelCache[syntaxTree] = semanticModel; return semanticModel; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorAnalysis.cs index 3004baf7..1d1b22ad 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorAnalysis.cs @@ -2,7 +2,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal interface ISubstituteConstructorAnalysis where TInvocationExpression : SyntaxNode +internal interface ISubstituteConstructorAnalysis { - ConstructorContext CollectConstructorContext(SubstituteContext substituteContext, ITypeSymbol proxyTypeSymbol); + ConstructorContext CollectConstructorContext(SubstituteContext substituteContext, ITypeSymbol proxyTypeSymbol); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorMatcher.cs index 74a36987..904df4af 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteConstructorMatcher.cs @@ -5,5 +5,8 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface ISubstituteConstructorMatcher { - bool MatchesInvocation(Compilation compilation, IMethodSymbol methodSymbol, IList invocationParameters); + bool MatchesInvocation( + Compilation compilation, + IMethodSymbol methodSymbol, + IReadOnlyList invocationParameters); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteProxyAnalysis.cs index 06cc04f7..1ed88cd1 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstituteProxyAnalysis.cs @@ -1,15 +1,12 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal interface ISubstituteProxyAnalysis where TInvocationExpressionSyntax : SyntaxNode where TExpressionSyntax : SyntaxNode +internal interface ISubstituteProxyAnalysis { - ITypeSymbol GetActualProxyTypeSymbol(SubstituteContext substituteContext); + ITypeSymbol GetActualProxyTypeSymbol(IInvocationOperation invocationOperation); - ImmutableArray GetProxySymbols(SubstituteContext substituteContext); - - ITypeSymbol GetActualProxyTypeSymbol(SemanticModel semanticModel, TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol); - - ImmutableArray GetProxySymbols(SemanticModel semanticModel, TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol); + ImmutableArray GetProxySymbols(IInvocationOperation invocationOperation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 04926a9d..0fde77fe 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -7,11 +7,11 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface ISubstitutionNodeFinder { - IEnumerable Find(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); + IEnumerable Find(Compilation compilation, IInvocationOperation invocationOperation); - IEnumerable FindForWhenExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation); + IEnumerable FindForWhenExpression(Compilation compilation, IInvocationOperation invocationOperation); - IEnumerable FindForReceivedInOrderExpression(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation, bool includeAll = false); + IEnumerable FindForReceivedInOrderExpression(Compilation compilation, IInvocationOperation invocationOperation, bool includeAll = false); IOperation FindForStandardExpression(IInvocationOperation invocationOperation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteContext.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteContext.cs index f98d97fa..53a1d28b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteContext.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteContext.cs @@ -1,21 +1,17 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal struct SubstituteContext - where TInvocationExpression : SyntaxNode +internal struct SubstituteContext { - public SyntaxNodeAnalysisContext SyntaxNodeAnalysisContext { get; } + public OperationAnalysisContext OperationAnalysisContext { get; } - public TInvocationExpression InvocationExpression { get; } + public IInvocationOperation InvocationOperation { get; } - public IMethodSymbol MethodSymbol { get; } - - public SubstituteContext(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, TInvocationExpression invocationExpression, IMethodSymbol methodSymbol) + public SubstituteContext(OperationAnalysisContext operationAnalysisContext, IInvocationOperation invocationOperation) { - SyntaxNodeAnalysisContext = syntaxNodeAnalysisContext; - InvocationExpression = invocationExpression; - MethodSymbol = methodSymbol; + OperationAnalysisContext = operationAnalysisContext; + InvocationOperation = invocationOperation; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index d90ce298..5cf7cc69 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -2,13 +2,14 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; using NSubstitute.Analyzers.VisualBasic.Refactorings; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider +internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider { public SubstituteForInternalMemberCodeFixProvider() : base(SubstituteProxyAnalysis.Instance) diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs index 89f71d22..f4b68686 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -9,10 +9,8 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer +internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer { - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - public SubstituteAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstituteProxyAnalysis.Instance, SubstituteConstructorAnalysis.Instance, SubstituteConstructorMatcher.Instance) { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs deleted file mode 100644 index d038206b..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -using NSubstitute.Analyzers.VisualBasic.Extensions; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal class SubstituteConstructorAnalysis : AbstractSubstituteConstructorAnalysis -{ - public static SubstituteConstructorAnalysis Instance { get; } = new (); - - private SubstituteConstructorAnalysis() - { - } - - protected override IList GetInvocationArguments(InvocationExpressionSyntax invocationExpression) - { - return invocationExpression.ArgumentList?.Arguments.ToList(); - } - - protected override IList GetParameterExpressionsFromArrayArgument(ArgumentSyntax syntaxNode) - { - return syntaxNode.GetExpression().GetParameterExpressionsFromArrayArgument()? - .Select(syntax => syntax).ToList(); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs deleted file mode 100644 index 8d371281..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -using NSubstitute.Analyzers.VisualBasic.Extensions; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal sealed class SubstituteProxyAnalysis : AbstractSubstituteProxyAnalysis -{ - public static SubstituteProxyAnalysis Instance { get; } = new (); - - private SubstituteProxyAnalysis() - { - } - - protected override IEnumerable GetTypeOfLikeExpressions(IList arrayParameters) - { - return arrayParameters.OfType(); - } - - protected override IEnumerable GetArrayInitializerArguments(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList?.Arguments.FirstOrDefault().GetExpression() - .GetParameterExpressionsFromArrayArgument(); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs deleted file mode 100644 index ba8cfdf0..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ /dev/null @@ -1,12 +0,0 @@ -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal sealed class SubstitutionNodeFinder : AbstractSubstitutionNodeFinder -{ - public static SubstitutionNodeFinder Instance { get; } = new (); - - private SubstitutionNodeFinder() - { - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/Extensions/SyntaxExtensions.cs b/src/NSubstitute.Analyzers.VisualBasic/Extensions/SyntaxExtensions.cs deleted file mode 100644 index 34957056..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/Extensions/SyntaxExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared.Extensions; - -namespace NSubstitute.Analyzers.VisualBasic.Extensions; - -internal static class SyntaxExtensions -{ - private static readonly int[] ParentInvocationKindHierarchy = - { - (int)SyntaxKind.SimpleMemberAccessExpression, - (int)SyntaxKind.InvocationExpression - }; - - public static InvocationExpressionSyntax GetParentInvocationExpression(this SyntaxNode node) - { - return node.GetParentNode(ParentInvocationKindHierarchy) as InvocationExpressionSyntax; - } - - public static SyntaxNode GetSubstitutionActualNode(this SyntaxNode node, Func symbolProvider) - { - return node.GetSubstitutionActualNode(symbolProvider); - } -} \ No newline at end of file From 06253e09d0d3c7a4d07fb62bae28a24097f8a36d Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sat, 16 Jul 2022 01:22:05 +0200 Subject: [PATCH 10/35] GH-153 - using operations api in code fix providers --- .../AbstractDiagnosticAnalyzersBenchmarks.cs | 4 +- .../ReEntrantSetupCodeFixProvider.cs | 24 +++----- ...stituteForInternalMemberCodeFixProvider.cs | 2 +- .../SyncOverAsyncThrowsCodeFixProvider.cs | 15 ++--- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 12 ++-- .../Extensions/SyntaxExtensions.cs | 14 ----- .../Refactorings/AddModifierRefactoring.cs | 32 +++++------ .../ReplaceModifierRefactoring.cs | 35 +++++------- ...teUsedForUnsupportedTypeCodeFixProvider.cs | 2 +- .../AbstractReEntrantSetupCodeFixProvider.cs | 4 +- ...stituteForInternalMemberCodeFixProvider.cs | 20 +++---- ...tractSuppressDiagnosticsCodeFixProvider.cs | 30 ++++------ ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 36 +++++++----- ...roduceSubstituteCodeRefactoringProvider.cs | 4 +- .../AbstractCallInfoFinder.cs | 15 ++--- ...stitutableMemberArgumentMatcherAnalyzer.cs | 32 ++++------- .../AbstractSubstituteAnalyzer.cs | 46 +++++++--------- .../AbstractSubstituteConstructorAnalysis.cs | 29 ++++------ .../AbstractSubstituteConstructorMatcher.cs | 2 +- .../IArgumentOperationExtensions.cs | 13 ----- .../Extensions/IOperationExtensions.cs | 55 +++++-------------- .../Extensions/SyntaxNodeExtensions.cs | 17 ------ .../ReEntrantSetupCodeFixProvider.cs | 36 ++++-------- ...stituteForInternalMemberCodeFixProvider.cs | 2 +- .../SyncOverAsyncThrowsCodeFixProvider.cs | 17 ++---- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 11 ++-- .../Refactorings/AddModifierRefactoring.cs | 28 ++++------ .../ReplaceModifierRefactoring.cs | 31 ++++------- .../SuppressDiagnosticSettingsVerifier.cs | 2 +- .../DocumentationTests/DocumentationTests.cs | 2 +- 30 files changed, 210 insertions(+), 362 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs index ce156a07..e8e092b8 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs @@ -186,10 +186,10 @@ private static HashSet RecursiveReferencedAssemblies( Assembly assembly, HashSet recursiveAssemblies = null) { - recursiveAssemblies = recursiveAssemblies ?? new HashSet(); + recursiveAssemblies ??= new HashSet(); if (recursiveAssemblies.Add(assembly)) { - foreach (AssemblyName referencedAssembly in assembly.GetReferencedAssemblies()) + foreach (var referencedAssembly in assembly.GetReferencedAssemblies()) { Assembly result; if (TryGetOrLoad(referencedAssembly, out result)) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs index e8a45d6f..45320844 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs @@ -34,25 +34,15 @@ protected override ArgumentSyntax CreateUpdatedParamsArgumentSyntaxNode( ArgumentSyntax argumentSyntaxNode) { var expression = argumentSyntaxNode.Expression; - ArrayCreationExpressionSyntax resultArrayCreationExpressionSyntax; - switch (expression) + var resultArrayCreationExpressionSyntax = expression switch { - case ArrayCreationExpressionSyntax arrayCreationExpressionSyntax: - resultArrayCreationExpressionSyntax = CreateArrayCreationExpression( - syntaxGenerator, - typeSymbol, - arrayCreationExpressionSyntax.Initializer); - break; - case ImplicitArrayCreationExpressionSyntax implicitArrayCreationExpressionSyntax: - resultArrayCreationExpressionSyntax = CreateArrayCreationExpression( - syntaxGenerator, - typeSymbol, - implicitArrayCreationExpressionSyntax.Initializer); - break; - default: - throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)); - } + ArrayCreationExpressionSyntax arrayCreationExpressionSyntax => CreateArrayCreationExpression( + syntaxGenerator, typeSymbol, arrayCreationExpressionSyntax.Initializer), + ImplicitArrayCreationExpressionSyntax implicitArrayCreationExpressionSyntax => + CreateArrayCreationExpression(syntaxGenerator, typeSymbol, implicitArrayCreationExpressionSyntax.Initializer), + _ => throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)) + }; return argumentSyntaxNode.WithExpression(resultArrayCreationExpressionSyntax); } diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index da455801..d5208f6d 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider +internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider { public SubstituteForInternalMemberCodeFixProvider() : base(SubstituteProxyAnalysis.Instance) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs index a1b2f234..af7fdb4a 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs @@ -1,22 +1,15 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class SyncOverAsyncThrowsCodeFixProvider : AbstractSyncOverAsyncThrowsCodeFixProvider +internal sealed class SyncOverAsyncThrowsCodeFixProvider : AbstractSyncOverAsyncThrowsCodeFixProvider { - protected override SyntaxNode GetExpression(InvocationExpressionSyntax invocationExpressionSyntax) => ((MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression).Expression; - - protected override SyntaxNode UpdateMemberExpression(InvocationExpressionSyntax invocationExpressionSyntax, SyntaxNode updatedNameSyntax) + public SyncOverAsyncThrowsCodeFixProvider() + : base(SubstitutionNodeFinder.Instance) { - var expressionSyntax = invocationExpressionSyntax.Expression; - return invocationExpressionSyntax.WithExpression(MemberAccessExpression( - expressionSyntax.Kind(), - ((MemberAccessExpressionSyntax)expressionSyntax).Expression, - (SimpleNameSyntax)updatedNameSyntax)); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs index 0176e59f..4a1c0f37 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -3,21 +3,23 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer +internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer { public SubstituteAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstituteProxyAnalysis.Instance, SubstituteConstructorAnalysis.Instance, SubstituteConstructorMatcher.Instance) { } - protected override InvocationExpressionSyntax GetCorrespondingSubstituteInvocationExpressionSyntax(InvocationExpressionSyntax invocationExpressionSyntax, string substituteName) + protected override SyntaxNode GetCorrespondingSubstituteInvocationExpressionSyntax(IInvocationOperation invocationOperation, string substituteName) { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; var memberAccessExpressionSyntax = (MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression; return invocationExpressionSyntax.WithExpression( @@ -25,11 +27,11 @@ protected override InvocationExpressionSyntax GetCorrespondingSubstituteInvocati memberAccessExpressionSyntax.Name.WithIdentifier(Identifier(substituteName)))); } - protected override InvocationExpressionSyntax GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments( - InvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + protected override SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(IInvocationOperation invocationOperation) { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; ArgumentListSyntax argumentListSyntax; - if (methodSymbol.IsGenericMethod) + if (invocationOperation.TargetMethod.IsGenericMethod) { argumentListSyntax = ArgumentList(); } diff --git a/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs b/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs deleted file mode 100644 index b1ea2200..00000000 --- a/src/NSubstitute.Analyzers.CSharp/Extensions/SyntaxExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.Shared.Extensions; - -namespace NSubstitute.Analyzers.CSharp.Extensions; - -internal static class SyntaxExtensions -{ - public static SyntaxNode GetSubstitutionActualNode(this SyntaxNode node, Func symbolProvider) - { - return node.GetSubstitutionActualNode(symbolProvider); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs index 4c6fdd30..18c17dcf 100644 --- a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs @@ -12,16 +12,11 @@ internal static class AddModifierRefactoring { public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) { - SyntaxKind syntaxKind; - - switch (accessibility) + var syntaxKind = accessibility switch { - case Accessibility.Protected: - syntaxKind = SyntaxKind.ProtectedKeyword; - break; - default: - throw new NotSupportedException($"Adding {accessibility} modifier is not supported"); - } + Accessibility.Protected => SyntaxKind.ProtectedKeyword, + _ => throw new NotSupportedException($"Adding {accessibility} modifier is not supported") + }; var newNode = Insert(node, syntaxKind); @@ -30,17 +25,16 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) { - switch (node) + return node switch { - case MethodDeclarationSyntax methodDeclarationSyntax: - return methodDeclarationSyntax.WithModifiers(UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)); - case PropertyDeclarationSyntax propertyDeclarationSyntax: - return propertyDeclarationSyntax.WithModifiers(UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)); - case IndexerDeclarationSyntax indexerDeclarationSyntax: - return indexerDeclarationSyntax.WithModifiers(UpdateModifiers(indexerDeclarationSyntax.Modifiers, syntaxKind)); - default: - throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported"); - } + MethodDeclarationSyntax methodDeclarationSyntax => methodDeclarationSyntax.WithModifiers( + UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)), + PropertyDeclarationSyntax propertyDeclarationSyntax => propertyDeclarationSyntax.WithModifiers( + UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)), + IndexerDeclarationSyntax indexerDeclarationSyntax => indexerDeclarationSyntax.WithModifiers( + UpdateModifiers(indexerDeclarationSyntax.Modifiers, syntaxKind)), + _ => throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported") + }; } private static SyntaxTokenList UpdateModifiers(SyntaxTokenList modifiers, SyntaxKind modifier) diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs index 653e5ecb..9bc6e64b 100644 --- a/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs @@ -23,35 +23,28 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) { - SyntaxKind syntaxKind; - switch (fromAccessibility) + var syntaxKind = fromAccessibility switch { - case Accessibility.Internal: - syntaxKind = SyntaxKind.InternalKeyword; - break; - case Accessibility.Public: - syntaxKind = SyntaxKind.PublicKeyword; - break; - default: - throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported"); - } + Accessibility.Internal => SyntaxKind.InternalKeyword, + Accessibility.Public => SyntaxKind.PublicKeyword, + _ => throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported") + }; return syntaxKind; } private static SyntaxNode ReplaceModifier(SyntaxNode node, SyntaxKind fromSyntaxKind, SyntaxKind toSyntaxKind) { - switch (node) + return node switch { - case MethodDeclarationSyntax methodDeclarationSyntax: - return methodDeclarationSyntax.WithModifiers(ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); - case PropertyDeclarationSyntax propertyDeclarationSyntax: - return propertyDeclarationSyntax.WithModifiers(ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); - case IndexerDeclarationSyntax indexerDeclarationSyntax: - return indexerDeclarationSyntax.WithModifiers(ReplaceModifier(indexerDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); - default: - throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported"); - } + MethodDeclarationSyntax methodDeclarationSyntax => methodDeclarationSyntax.WithModifiers( + ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)), + PropertyDeclarationSyntax propertyDeclarationSyntax => propertyDeclarationSyntax.WithModifiers( + ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)), + IndexerDeclarationSyntax indexerDeclarationSyntax => indexerDeclarationSyntax.WithModifiers( + ReplaceModifier(indexerDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)), + _ => throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported") + }; } private static SyntaxTokenList ReplaceModifier(SyntaxTokenList modifiers, SyntaxKind fromModifier, SyntaxKind toModifier) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index b5d45ef4..a49db4e4 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -27,7 +27,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var invocationExpression = (TInvocationExpression)root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - if (!(semanticModel.GetSymbolInfo(invocationExpression).Symbol is IMethodSymbol methodSymbol)) + if (semanticModel.GetSymbolInfo(invocationExpression).Symbol is not IMethodSymbol methodSymbol) { return; } diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs index 7b1eeaa8..5579cb4f 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs @@ -70,7 +70,7 @@ private async Task CreateChangedDocument( var documentEditor = await DocumentEditor.CreateAsync(context.Document, ct); var semanticModel = await context.Document.GetSemanticModelAsync(ct); var invocationSyntaxNode = argumentListSyntax.Parent; - if (!(semanticModel.GetSymbolInfo(invocationSyntaxNode).Symbol is IMethodSymbol methodSymbol)) + if (semanticModel.GetSymbolInfo(invocationSyntaxNode).Symbol is not IMethodSymbol methodSymbol) { return context.Document; } @@ -84,7 +84,7 @@ private async Task CreateChangedDocument( { if (IsArrayParamsArgument(semanticModel, argumentSyntax)) { - lambdaType = lambdaType ?? ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); + lambdaType ??= ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); var updatedParamsArgumentSyntaxNode = CreateUpdatedParamsArgumentSyntaxNode( SyntaxGenerator.GetGenerator(context.Document), lambdaType, diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index f5bdf42a..eab32bd9 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -8,9 +8,7 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractSubstituteForInternalMemberCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider - where TInvocationExpressionSyntax : SyntaxNode - where TCompilationUnitSyntax : SyntaxNode +internal abstract class AbstractSubstituteForInternalMemberCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider where TCompilationUnitSyntax : SyntaxNode { private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; @@ -31,13 +29,16 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var findNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); - if (!(findNode is TInvocationExpressionSyntax invocationExpression)) + var invocationExpression = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); + + if (invocationExpression is not { } || + semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) { return; } - var syntaxReference = await GetDeclaringSyntaxReference(context, invocationExpression); + var syntaxReference = GetDeclaringSyntaxReference(invocationOperation); if (syntaxReference == null) { @@ -57,13 +58,10 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) protected abstract void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, TCompilationUnitSyntax compilationUnitSyntax); - private async Task GetDeclaringSyntaxReference(CodeFixContext context, TInvocationExpressionSyntax invocationExpression) + private SyntaxReference GetDeclaringSyntaxReference(IInvocationOperation invocationOperation) { - var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - var invocationOperation = semanticModel.GetOperation(invocationExpression) as IInvocationOperation; var actualProxyTypeSymbol = _substituteProxyAnalysis.GetActualProxyTypeSymbol(invocationOperation); - var syntaxReference = actualProxyTypeSymbol.DeclaringSyntaxReferences.FirstOrDefault(); - return syntaxReference; + return actualProxyTypeSymbol.DeclaringSyntaxReferences.FirstOrDefault(); } private TCompilationUnitSyntax FindCompilationUnitSyntax(SyntaxNode syntaxNode) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs index 8ff16c48..22fe430b 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs @@ -27,7 +27,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var settingsFile = GetSettingsFile(project); - // creating additional document from Roslyn is broken (https://github.com/dotnet/roslyn/issues/4655) the nsubstitute.json file have to be created by users manually + // creating additional document from Roslyn is broken (https://github.com/dotnet/roslyn/issues/4655) the nsubstitute.json file has to be created by users manually // if there is no settings file do not provide refactorings if (settingsFile == null) { @@ -62,7 +62,7 @@ protected virtual IEnumerable GetSuppressibleSymbol(SemanticModel model yield return symbol; - if (!(symbol is ITypeSymbol)) + if (symbol is not ITypeSymbol) { yield return symbol.ContainingType; yield return symbol.ContainingType.ContainingNamespace; @@ -82,21 +82,15 @@ private static string CreateCodeFixTitle(Diagnostic diagnostic, ISymbol innerSym private static string GetSymbolTitlePrefix(ISymbol innerSymbol) { - switch (innerSymbol) + return innerSymbol switch { - case IMethodSymbol _: - return "method"; - case IPropertySymbol propertySymbol when propertySymbol.IsIndexer: - return "indexer"; - case IPropertySymbol _: - return "property"; - case ITypeSymbol _: - return "class"; - case INamespaceSymbol _: - return "namespace"; - default: - return string.Empty; - } + IMethodSymbol _ => "method", + IPropertySymbol { IsIndexer: true } => "indexer", + IPropertySymbol _ => "property", + ITypeSymbol _ => "class", + INamespaceSymbol _ => "namespace", + _ => string.Empty + }; } private Task GetTransformedSolutionAsync(CodeFixContext context, Diagnostic diagnostic, TextDocument settingsFile, ISymbol symbol) @@ -128,13 +122,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(); + options.Suppressions ??= new List(); var existingSuppression = options.Suppressions.FirstOrDefault(suppression => suppression.Target == target); if (existingSuppression != null) { - existingSuppression.Rules = existingSuppression.Rules ?? new List(); + existingSuppression.Rules ??= new List(); existingSuppression.Rules.Add(diagnostic.Id); } else diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 9ec94477..56a59803 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -7,13 +7,20 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Operations; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractSyncOverAsyncThrowsCodeFixProvider : CodeFixProvider - where TInvocationExpressionSyntax : SyntaxNode +internal abstract class AbstractSyncOverAsyncThrowsCodeFixProvider : CodeFixProvider { + private readonly ISubstitutionNodeFinder _substitutionNodeFinder; + + protected AbstractSyncOverAsyncThrowsCodeFixProvider(ISubstitutionNodeFinder substitutionNodeFinder) + { + _substitutionNodeFinder = substitutionNodeFinder; + } + public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SyncOverAsyncThrows); @@ -31,8 +38,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (!(root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is - TInvocationExpressionSyntax invocation)) + if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocation) { return; } @@ -51,19 +57,17 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var codeAction = CodeAction.Create( $"Replace with {replacementMethod}", ct => CreateChangedDocument(context, semanticModel, invocation, methodSymbol, supportsThrowsAsync, ct), - nameof(AbstractSyncOverAsyncThrowsCodeFixProvider)); + nameof(AbstractSyncOverAsyncThrowsCodeFixProvider)); context.RegisterCodeFix(codeAction, diagnostic); } - protected abstract SyntaxNode GetExpression(TInvocationExpressionSyntax invocationExpressionSyntax); - - protected abstract SyntaxNode UpdateMemberExpression(TInvocationExpressionSyntax invocationExpressionSyntax, SyntaxNode updatedNameSyntax); + protected abstract SyntaxNode UpdateMemberExpression(SyntaxNode invocationExpressionSyntax, SyntaxNode updatedNameSyntax); private async Task CreateChangedDocument( CodeFixContext context, SemanticModel semanticModel, - TInvocationExpressionSyntax currentInvocationExpression, + SyntaxNode currentInvocationExpression, IMethodSymbol invocationSymbol, bool useModernSyntax, CancellationToken cancellationToken) @@ -88,7 +92,7 @@ private async Task CreateChangedDocument( } private async Task CreateThrowsAsyncInvocationExpression( - TInvocationExpressionSyntax currentInvocationExpression, + SyntaxNode currentInvocationExpression, IMethodSymbol invocationSymbol, CodeFixContext context) { @@ -108,7 +112,7 @@ private async Task CreateThrowsAsyncInvocationExpression( } private async Task CreateReturnInvocationExpression( - TInvocationExpressionSyntax currentInvocationExpression, + SyntaxNode currentInvocationExpression, IInvocationOperation invocationOperation, IMethodSymbol invocationSymbol, CodeFixContext context) @@ -134,13 +138,14 @@ private async Task CreateReturnInvocationExpression( return CreateReturnExtensionInvocationExpression( currentInvocationExpression, + invocationOperation, syntaxGenerator, fromExceptionInvocationExpression, returnsMethodName); } private static SyntaxNode CreateReturnOrdinalInvocationExpression( - TInvocationExpressionSyntax currentInvocationExpression, + SyntaxNode currentInvocationExpression, IInvocationOperation invocationOperation, SyntaxGenerator syntaxGenerator, SyntaxNode fromExceptionInvocationExpression, @@ -154,15 +159,16 @@ private static SyntaxNode CreateReturnOrdinalInvocationExpression( } private SyntaxNode CreateReturnExtensionInvocationExpression( - TInvocationExpressionSyntax currentInvocationExpression, + SyntaxNode currentInvocationExpression, + IInvocationOperation invocationOperation, SyntaxGenerator syntaxGenerator, SyntaxNode fromExceptionInvocationExpression, string returnsMethodName) { - var expressionSyntax = GetExpression(currentInvocationExpression); + var substituteNodeSyntax = _substitutionNodeFinder.FindForStandardExpression(invocationOperation).Syntax; var accessExpression = - syntaxGenerator.MemberAccessExpression(expressionSyntax, returnsMethodName); + syntaxGenerator.MemberAccessExpression(substituteNodeSyntax, returnsMethodName); return syntaxGenerator.InvocationExpression(accessExpression, fromExceptionInvocationExpression) .WithTriviaFrom(currentInvocationExpression); diff --git a/src/NSubstitute.Analyzers.Shared/CodeRefactoringProviders/AbstractIntroduceSubstituteCodeRefactoringProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeRefactoringProviders/AbstractIntroduceSubstituteCodeRefactoringProvider.cs index 981543f9..26af1585 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeRefactoringProviders/AbstractIntroduceSubstituteCodeRefactoringProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeRefactoringProviders/AbstractIntroduceSubstituteCodeRefactoringProvider.cs @@ -21,8 +21,8 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var node = root.FindNode(context.Span); - if (!(node is TArgumentListSyntax argumentListSyntax) || - !(node.Parent is TObjectCreationExpressionSyntax objectCreationExpressionSyntax)) + if (node is not TArgumentListSyntax argumentListSyntax || + node.Parent is not TObjectCreationExpressionSyntax objectCreationExpressionSyntax) { return; } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs index 152b0026..56710912 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs @@ -70,16 +70,13 @@ private static IParameterReferenceOperation FindMatchingParameterReference(Seman private static IParameterReferenceOperation FindMatchingParameterReference(IOperation operation) { - IParameterReferenceOperation parameterReferenceOperation = null; - switch (operation) + var parameterReferenceOperation = operation switch { - case IInvocationOperation invocationOperation: - parameterReferenceOperation = invocationOperation.Instance as IParameterReferenceOperation; - break; - case IPropertyReferenceOperation propertyReferenceOperation: - parameterReferenceOperation = propertyReferenceOperation.Instance as IParameterReferenceOperation; - break; - } + IInvocationOperation invocationOperation => invocationOperation.Instance as IParameterReferenceOperation, + IPropertyReferenceOperation propertyReferenceOperation => + propertyReferenceOperation.Instance as IParameterReferenceOperation, + _ => null + }; if (parameterReferenceOperation != null) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs index 0609104e..ca30403b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -50,7 +50,7 @@ private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - if (!(methodSymbolInfo.Symbol is IMethodSymbol methodSymbol)) + if (methodSymbolInfo.Symbol is not IMethodSymbol methodSymbol) { return; } @@ -239,26 +239,18 @@ private bool IsWithinWhenLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, private static IMemberReferenceOperation GetMemberReferenceOperation(IOperation operation) { - switch (operation) + return operation switch { - case IAssignmentOperation assignmentOperation - when assignmentOperation.Target is IMemberReferenceOperation memberReferenceOperation: - return memberReferenceOperation; - case IBinaryOperation binaryOperation - when binaryOperation.LeftOperand is IMemberReferenceOperation binaryMemberReferenceOperation: - return binaryMemberReferenceOperation; - case IBinaryOperation binaryOperation - when binaryOperation.LeftOperand is IConversionOperation conversionOperation && - conversionOperation.Operand is IMemberReferenceOperation conversionMemberReference: - return conversionMemberReference; - case IExpressionStatementOperation expressionStatementOperation - when - expressionStatementOperation.Operation is ISimpleAssignmentOperation simpleAssignmentOperation && - simpleAssignmentOperation.Target is IMemberReferenceOperation memberReferenceOperation: - return memberReferenceOperation; - default: - return null; - } + IAssignmentOperation { Target: IMemberReferenceOperation memberReferenceOperation } => + memberReferenceOperation, + IBinaryOperation { LeftOperand: IMemberReferenceOperation binaryMemberReferenceOperation } => + binaryMemberReferenceOperation, + IBinaryOperation { LeftOperand: IConversionOperation { Operand: IMemberReferenceOperation conversionMemberReference } } => + conversionMemberReference, + IExpressionStatementOperation { Operation: ISimpleAssignmentOperation { Target: IMemberReferenceOperation memberReferenceOperation } } => + memberReferenceOperation, + _ => null + }; } private SyntaxNode FindMaybeAllowedEnclosingExpression(TInvocationExpressionSyntax invocationExpression) => diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs index 1b4a0118..03ff5d74 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractSubstituteAnalyzer : AbstractDiagnosticAnalyzer where TInvocationExpressionSyntax : SyntaxNode +internal abstract class AbstractSubstituteAnalyzer : AbstractDiagnosticAnalyzer { private readonly ISubstituteProxyAnalysis _substituteProxyAnalysis; private readonly ISubstituteConstructorAnalysis _substituteConstructorAnalysis; @@ -38,9 +38,9 @@ protected AbstractSubstituteAnalyzer( DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForDelegate); } - protected abstract TInvocationExpressionSyntax GetCorrespondingSubstituteInvocationExpressionSyntax(TInvocationExpressionSyntax invocationExpressionSyntax, string substituteName); + protected abstract SyntaxNode GetCorrespondingSubstituteInvocationExpressionSyntax(IInvocationOperation invocationOperation, string substituteName); - protected abstract TInvocationExpressionSyntax GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(TInvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol); + protected abstract SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(IInvocationOperation invocationOperation); public override ImmutableArray SupportedDiagnostics { get; } @@ -93,7 +93,7 @@ private void AnalyzeSubstitute(SubstituteContext substituteContext) return; } - if (AnalyzeTypeAccessability(substituteContext, proxyType)) + if (AnalyzeTypeAccessibility(substituteContext, proxyType)) { return; } @@ -121,7 +121,7 @@ private void AnalyzePartialSubstitute(SubstituteContext substituteContext) return; } - if (AnalyzeTypeAccessability(substituteContext, proxyType)) + if (AnalyzeTypeAccessibility(substituteContext, proxyType)) { return; } @@ -176,7 +176,7 @@ private bool AnalyzeConstructorParametersCount(SubstituteContext substituteConte var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForInterface, substituteContext.InvocationOperation.Syntax.GetLocation(), - GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod)); + GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(substituteContext.InvocationOperation)); substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); return true; @@ -186,7 +186,7 @@ private bool AnalyzeConstructorParametersCount(SubstituteContext substituteConte var delegateDiagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForDelegate, substituteContext.InvocationOperation.Syntax.GetLocation(), - GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod)); + GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(substituteContext.InvocationOperation)); substituteContext.OperationAnalysisContext.ReportDiagnostic(delegateDiagnostic); return true; @@ -212,12 +212,12 @@ private bool AnalyzeConstructorParametersCount(SubstituteContext substituteConte private bool AnalyzeTypeKind(SubstituteContext substituteContext, ITypeSymbol proxyType) { - if (proxyType.TypeKind == TypeKind.Interface || proxyType.TypeKind == TypeKind.Delegate) + if (proxyType.TypeKind is TypeKind.Interface or TypeKind.Delegate) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.PartialSubstituteForUnsupportedType, substituteContext.InvocationOperation.Syntax.GetLocation(), - GetCorrespondingSubstituteMethod(substituteContext.InvocationOperation.Syntax, substituteContext.InvocationOperation.TargetMethod), + GetCorrespondingSubstituteMethod(substituteContext.InvocationOperation), substituteContext.InvocationOperation.Syntax); substituteContext.OperationAnalysisContext.ReportDiagnostic(diagnostic); @@ -227,7 +227,7 @@ private bool AnalyzeTypeKind(SubstituteContext substituteContext, ITypeSymbol pr return false; } - private bool AnalyzeTypeAccessability(SubstituteContext substituteContext, ITypeSymbol proxyType) + private bool AnalyzeTypeAccessibility(SubstituteContext substituteContext, ITypeSymbol proxyType) { if (proxyType.DeclaredAccessibility == Accessibility.Internal && proxyType.InternalsVisibleToProxyGenerator() == false) { @@ -285,23 +285,17 @@ private bool AnalyzeConstructorAccessibility(SubstituteContext substituteContext return false; } - private string GetCorrespondingSubstituteMethod(SyntaxNode syntaxNode, IMethodSymbol methodSymbol) + private string GetCorrespondingSubstituteMethod(IInvocationOperation invocationOperation) { - var invocationExpressionSyntax = (TInvocationExpressionSyntax)syntaxNode; - switch (methodSymbol.Name) + return invocationOperation.TargetMethod.Name switch { - case MetadataNames.SubstituteFactoryCreatePartial: - return GetCorrespondingSubstituteInvocationExpressionSyntax(invocationExpressionSyntax, MetadataNames.SubstituteFactoryCreate).ToString(); - case MetadataNames.NSubstituteForPartsOfMethod: - return GetCorrespondingSubstituteInvocationExpressionSyntax(invocationExpressionSyntax, MetadataNames.NSubstituteForMethod).ToString(); - default: - return string.Empty; - } - } - - private string GetSubstituteMethodWithoutConstructorArguments(SyntaxNode invocationExpressionSyntax, IMethodSymbol methodSymbol) - { - return GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments( - (TInvocationExpressionSyntax)invocationExpressionSyntax, methodSymbol).ToString(); + MetadataNames.SubstituteFactoryCreatePartial => GetCorrespondingSubstituteInvocationExpressionSyntax( + invocationOperation, MetadataNames.SubstituteFactoryCreate) + .ToString(), + MetadataNames.NSubstituteForPartsOfMethod => GetCorrespondingSubstituteInvocationExpressionSyntax( + invocationOperation, MetadataNames.NSubstituteForMethod) + .ToString(), + _ => string.Empty + }; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs index de6dd48c..d774d1db 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; @@ -69,13 +68,15 @@ private ITypeSymbol[] GetGenericInvocationArgumentTypes(SubstituteContext substi return TypeSymbols(arrayTypeSymbol); } - return arguments.SelectMany(ArgType).ToArray(); + return arguments.SelectMany(GetArgumentType).ToArray(); } private ITypeSymbol[] GetNonGenericInvocationArgumentTypes(SubstituteContext substituteContext) { // Substitute.For(new [] { typeof(T) }, new object[] { 1, 2, 3}) // actual arguments reside in second arg - var arrayArgument = GetInvocationArguments(substituteContext).Skip(1).FirstOrDefault(); + var arrayArgument = substituteContext.InvocationOperation.GetOrderedArgumentOperations().Skip(1) + .FirstOrDefault(); + if (arrayArgument == null) { return null; @@ -87,7 +88,7 @@ private ITypeSymbol[] GetNonGenericInvocationArgumentTypes(SubstituteContext sub return TypeSymbols(arrayTypeSymbol); } - return ArgType(arrayArgument); + return GetArgumentType(arrayArgument); } private IMethodSymbol[] GetAccessibleConstructors(ITypeSymbol genericArgument) @@ -107,8 +108,7 @@ bool IsVisibleToProxy(IMethodSymbol symbol) return false; } - return symbol.DeclaredAccessibility == Accessibility.Internal || - symbol.DeclaredAccessibility == Accessibility.ProtectedOrInternal; + return symbol.DeclaredAccessibility is Accessibility.Internal or Accessibility.ProtectedOrInternal; } return genericArgument.GetMembers().OfType().Where(symbol => @@ -117,11 +117,6 @@ bool IsVisibleToProxy(IMethodSymbol symbol) (IsAccessible(symbol) || IsVisibleToProxy(symbol))).ToArray(); } - private IEnumerable GetInvocationArguments(SubstituteContext substituteContext) - { - return substituteContext.InvocationOperation.GetOrderedArgumentOperations(); - } - private ITypeSymbol[] TypeSymbols(IArrayCreationOperation arrayInitializerOperation) { return arrayInitializerOperation.Initializer.ElementValues.Select(item => @@ -131,15 +126,15 @@ item is IConversionOperation conversionOperation .ToArray(); } - private ITypeSymbol[] ArgType(IArgumentOperation x) + private ITypeSymbol[] GetArgumentType(IArgumentOperation argumentOperation) { - if (x.ArgumentKind == ArgumentKind.ParamArray) + if (argumentOperation.ArgumentKind != ArgumentKind.ParamArray) { - var arrayInitializerOperation = x.Value as IArrayCreationOperation; - - return TypeSymbols(arrayInitializerOperation); + return Array.Empty(); } - return Array.Empty(); + var arrayInitializerOperation = argumentOperation.Value as IArrayCreationOperation; + + return TypeSymbols(arrayInitializerOperation); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs index 753ac5db..e7d194b1 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs @@ -55,7 +55,7 @@ private bool MatchesInvocation(Compilation compilation, IParameterSymbol symbol, ClassifyConversion(compilation, invocationParameters[symbol.Ordinal], symbol.Type); } - if (!(symbol.Type is IArrayTypeSymbol arrayTypeSymbol)) + if (symbol.Type is not IArrayTypeSymbol arrayTypeSymbol) { return false; } diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IArgumentOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IArgumentOperationExtensions.cs index f673c54b..cd135302 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IArgumentOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IArgumentOperationExtensions.cs @@ -5,19 +5,6 @@ namespace NSubstitute.Analyzers.Shared.Extensions; internal static class IArgumentOperationExtensions { - public static ITypeSymbol GetArgumentOperationActualTypeSymbol(this IArgumentOperation argumentOperation) - { - ITypeSymbol conversionTypeSymbol = null; - switch (argumentOperation.Value) - { - case IConversionOperation conversionOperation: - conversionTypeSymbol = conversionOperation.Operand.Type; - break; - } - - return conversionTypeSymbol ?? argumentOperation.GetArgumentOperationDeclaredTypeSymbol(); - } - public static ITypeSymbol GetArgumentOperationDeclaredTypeSymbol(this IArgumentOperation argumentOperation) { return argumentOperation.Parameter.Type; diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 0c32aca2..02965dbc 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -9,17 +9,14 @@ internal static class IOperationExtensions { public static bool IsEventAssignmentOperation(this IOperation operation) { - switch (operation) + return operation switch { - case IAssignmentOperation assignmentOperation: - return assignmentOperation.Kind == OperationKind.EventAssignment; - case IEventAssignmentOperation _: - return true; - case IExpressionStatementOperation expressionStatementOperation: - return IsEventAssignmentOperation(expressionStatementOperation.Operation); - default: - return false; - } + IAssignmentOperation assignmentOperation => assignmentOperation.Kind == OperationKind.EventAssignment, + IEventAssignmentOperation _ => true, + IExpressionStatementOperation expressionStatementOperation => IsEventAssignmentOperation( + expressionStatementOperation.Operation), + _ => false + }; } public static IOperation GetSubstituteOperation(this IInvocationOperation invocationOperation) @@ -59,24 +56,6 @@ public static IEnumerable GetOrderedArgumentOperationsWithou return orderedArguments.Skip(1); } - public static IEnumerable GetSyntaxes(this IArgumentOperation argumentOperation) - { - if (argumentOperation.Parameter.IsParams) - { - var initializerElementValues = - (argumentOperation.Value as IArrayCreationOperation)?.Initializer.ElementValues; - - foreach (var operation in initializerElementValues ?? Enumerable.Empty()) - { - yield return operation.Syntax; - } - - yield break; - } - - yield return argumentOperation.Value.Syntax; - } - public static int? GetIndexerPosition(this IOperation operation) { var literal = operation switch @@ -100,26 +79,22 @@ public static IEnumerable GetSyntaxes(this IArgumentOperation argume public static ITypeSymbol GetTypeSymbol(this IArgumentOperation argumentOperation) { - ITypeSymbol conversionTypeSymbol = null; - switch (argumentOperation.Value) + var conversionTypeSymbol = argumentOperation.Value switch { - case IConversionOperation conversionOperation: - conversionTypeSymbol = conversionOperation.Operand.Type; - break; - } + IConversionOperation conversionOperation => conversionOperation.Operand.Type, + _ => null + }; return conversionTypeSymbol ?? argumentOperation.GetArgumentOperationDeclaredTypeSymbol(); } public static ITypeSymbol GetTypeSymbol(this IAssignmentOperation assignmentOperation) { - ITypeSymbol conversionTypeSymbol = null; - switch (assignmentOperation.Value) + var conversionTypeSymbol = assignmentOperation.Value switch { - case IConversionOperation conversionOperation: - conversionTypeSymbol = conversionOperation.Operand.Type; - break; - } + IConversionOperation conversionOperation => conversionOperation.Operand.Type, + _ => null + }; return conversionTypeSymbol ?? assignmentOperation.Value.Type; } diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs index 3a730d5b..58c52cbe 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; @@ -11,22 +10,6 @@ public static SyntaxNode GetParentNode(this SyntaxNode syntaxNode, IEnumerable(this SyntaxNode node, ISymbol symbol) - where TMemberAccessExpression : SyntaxNode - { - var actualNode = node.GetSubstitutionActualNode(syntax => symbol); - - return actualNode.GetLocation(); - } - - public static SyntaxNode GetSubstitutionActualNode(this SyntaxNode node, Func symbolProvider) - where TMemberAccessExpression : SyntaxNode - { - var actualNode = node is TMemberAccessExpression && symbolProvider(node) is IMethodSymbol _ ? node.Parent : node; - - return actualNode; - } - private static SyntaxNode GetNodeInHierarchy(IEnumerable nodes, IEnumerable hierarchyKindPath) { using (var descendantNodesEnumerator = nodes.GetEnumerator()) diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs index e9c3dabc..ad3495a7 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs @@ -22,42 +22,30 @@ protected override ArgumentSyntax CreateUpdatedArgumentSyntaxNode(ArgumentSyntax var lambdaExpression = CreateSingleLineLambdaExpression(expressionSyntax); - switch (argumentSyntaxNode) + return argumentSyntaxNode switch { - case SimpleArgumentSyntax simpleArgumentSyntax: - return simpleArgumentSyntax.WithExpression(lambdaExpression); - } - - return argumentSyntaxNode; + SimpleArgumentSyntax simpleArgumentSyntax => simpleArgumentSyntax.WithExpression(lambdaExpression), + _ => argumentSyntaxNode + }; } protected override ArgumentSyntax CreateUpdatedParamsArgumentSyntaxNode(SyntaxGenerator syntaxGenerator, ITypeSymbol typeSymbol, ArgumentSyntax argumentSyntaxNode) { - if (!(argumentSyntaxNode is SimpleArgumentSyntax simpleArgumentSyntax)) + if (argumentSyntaxNode is not SimpleArgumentSyntax simpleArgumentSyntax) { return argumentSyntaxNode; } var expression = argumentSyntaxNode.GetExpression(); - ArrayCreationExpressionSyntax resultArrayCreationExpressionSyntax; - switch (expression) + var resultArrayCreationExpressionSyntax = expression switch { - case ArrayCreationExpressionSyntax arrayCreationExpressionSyntax: - resultArrayCreationExpressionSyntax = CreateArrayCreationExpression( - syntaxGenerator, - typeSymbol, - arrayCreationExpressionSyntax.Initializer.Initializers); - break; - case CollectionInitializerSyntax implicitArrayCreationExpressionSyntax: - resultArrayCreationExpressionSyntax = CreateArrayCreationExpression( - syntaxGenerator, - typeSymbol, - implicitArrayCreationExpressionSyntax.Initializers); - break; - default: - throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)); - } + ArrayCreationExpressionSyntax arrayCreationExpressionSyntax => CreateArrayCreationExpression( + syntaxGenerator, typeSymbol, arrayCreationExpressionSyntax.Initializer.Initializers), + CollectionInitializerSyntax implicitArrayCreationExpressionSyntax => CreateArrayCreationExpression( + syntaxGenerator, typeSymbol, implicitArrayCreationExpressionSyntax.Initializers), + _ => throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)) + }; return simpleArgumentSyntax.WithExpression(resultArrayCreationExpressionSyntax); } diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index 5cf7cc69..af372ac7 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider +internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider { public SubstituteForInternalMemberCodeFixProvider() : base(SubstituteProxyAnalysis.Instance) diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs index 28323f7f..2c397a31 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs @@ -1,24 +1,15 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; -using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class SyncOverAsyncThrowsCodeFixProvider : AbstractSyncOverAsyncThrowsCodeFixProvider +internal sealed class SyncOverAsyncThrowsCodeFixProvider : AbstractSyncOverAsyncThrowsCodeFixProvider { - protected override SyntaxNode GetExpression(InvocationExpressionSyntax invocationExpressionSyntax) => ((MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression).Expression; - - protected override SyntaxNode UpdateMemberExpression(InvocationExpressionSyntax invocationExpressionSyntax, SyntaxNode updatedNameSyntax) + public SyncOverAsyncThrowsCodeFixProvider() + : base(SubstitutionNodeFinder.Instance) { - var expressionSyntax = invocationExpressionSyntax.Expression; - return invocationExpressionSyntax.WithExpression(MemberAccessExpression( - expressionSyntax.Kind(), - ((MemberAccessExpressionSyntax)expressionSyntax).Expression, - Token(SyntaxKind.DotToken), - (SimpleNameSyntax)updatedNameSyntax)); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs index f4b68686..74baac8a 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -9,15 +10,16 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer +internal sealed class SubstituteAnalyzer : AbstractSubstituteAnalyzer { public SubstituteAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstituteProxyAnalysis.Instance, SubstituteConstructorAnalysis.Instance, SubstituteConstructorMatcher.Instance) { } - protected override InvocationExpressionSyntax GetCorrespondingSubstituteInvocationExpressionSyntax(InvocationExpressionSyntax invocationExpressionSyntax, string substituteName) + protected override SyntaxNode GetCorrespondingSubstituteInvocationExpressionSyntax(IInvocationOperation invocationOperation, string substituteName) { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; var memberAccessExpressionSyntax = (MemberAccessExpressionSyntax)invocationExpressionSyntax.Expression; return invocationExpressionSyntax.WithExpression( @@ -25,10 +27,11 @@ protected override InvocationExpressionSyntax GetCorrespondingSubstituteInvocati memberAccessExpressionSyntax.Name.WithIdentifier(Identifier(substituteName)))); } - protected override InvocationExpressionSyntax GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(InvocationExpressionSyntax invocationExpressionSyntax, IMethodSymbol methodSymbol) + protected override SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(IInvocationOperation invocationOperation) { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; ArgumentListSyntax argumentListSyntax; - if (methodSymbol.IsGenericMethod) + if (invocationOperation.TargetMethod.IsGenericMethod) { argumentListSyntax = ArgumentList(); } diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs index 67507c78..9f785ece 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs @@ -12,16 +12,11 @@ internal static class AddModifierRefactoring { public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) { - SyntaxKind syntaxKind; - - switch (accessibility) + var syntaxKind = accessibility switch { - case Accessibility.Protected: - syntaxKind = SyntaxKind.ProtectedKeyword; - break; - default: - throw new NotSupportedException($"Adding {accessibility} modifier is not supported"); - } + Accessibility.Protected => SyntaxKind.ProtectedKeyword, + _ => throw new NotSupportedException($"Adding {accessibility} modifier is not supported") + }; var newNode = Insert(node, syntaxKind); @@ -30,15 +25,14 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) { - switch (node) + return node switch { - case MethodStatementSyntax methodDeclarationSyntax: - return methodDeclarationSyntax.WithModifiers(UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)); - case PropertyStatementSyntax propertyDeclarationSyntax: - return propertyDeclarationSyntax.WithModifiers(UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)); - default: - throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported"); - } + MethodStatementSyntax methodDeclarationSyntax => methodDeclarationSyntax.WithModifiers( + UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)), + PropertyStatementSyntax propertyDeclarationSyntax => propertyDeclarationSyntax.WithModifiers( + UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)), + _ => throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported") + }; } private static SyntaxTokenList UpdateModifiers(SyntaxTokenList modifiers, SyntaxKind modifier) diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs index 29e9ea5e..535ece9c 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs @@ -23,33 +23,26 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) { - SyntaxKind syntaxKind; - switch (fromAccessibility) + var syntaxKind = fromAccessibility switch { - case Accessibility.Internal: - syntaxKind = SyntaxKind.FriendKeyword; - break; - case Accessibility.Public: - syntaxKind = SyntaxKind.PublicKeyword; - break; - default: - throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported"); - } + Accessibility.Internal => SyntaxKind.FriendKeyword, + Accessibility.Public => SyntaxKind.PublicKeyword, + _ => throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported") + }; return syntaxKind; } private static SyntaxNode ReplaceModifier(SyntaxNode node, SyntaxKind fromSyntaxKind, SyntaxKind toSyntaxKind) { - switch (node) + return node switch { - case MethodStatementSyntax methodDeclarationSyntax: - return methodDeclarationSyntax.WithModifiers(ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); - case PropertyStatementSyntax propertyDeclarationSyntax: - return propertyDeclarationSyntax.WithModifiers(ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); - default: - throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported"); - } + MethodStatementSyntax methodDeclarationSyntax => methodDeclarationSyntax.WithModifiers( + ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)), + PropertyStatementSyntax propertyDeclarationSyntax => propertyDeclarationSyntax.WithModifiers( + ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)), + _ => throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported") + }; } private static SyntaxTokenList ReplaceModifier(SyntaxTokenList modifiers, SyntaxKind fromModifier, SyntaxKind toModifier) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs index c3e98502..6452edd7 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs @@ -83,7 +83,7 @@ private static AnalyzersSettings GetExpectedSettings(AnalyzersSettings originalS var targetSuppression = originalSupressions.SingleOrDefault(suppression => suppression.Target == target); if (targetSuppression != null) { - targetSuppression.Rules = targetSuppression.Rules ?? new List(); + targetSuppression.Rules ??= new List(); targetSuppression.Rules.Add(diagnosticRuleId); } else diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs index ee213310..053da12f 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs @@ -116,7 +116,7 @@ private List GetLayoutByHeadings(List blocks) blockedLayout.Add(currentContainer); } - if (currentHeadingBlock != null && !(currentBlock is HeadingBlock)) + if (currentHeadingBlock != null && currentBlock is not HeadingBlock) { currentContainer.Children.Add(currentBlock); } From baa7506cefe9b2368dff668d21b0c98291c58030 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sat, 23 Jul 2022 15:37:37 +0200 Subject: [PATCH 11/35] GH-153 - using operations api in NonSubstitutableMemberArgumentMatcherAnalyzer --- ...tcherSuppressDiagnosticsCodeFixProvider.cs | 3 +- ...stitutableMemberArgumentMatcherAnalyzer.cs | 22 +- .../AbstractNonSubstitutableMemberAnalysis.cs | 1 + ...stitutableMemberArgumentMatcherAnalyzer.cs | 192 +++++++----------- .../Extensions/IOperationExtensions.cs | 16 ++ ...tcherSuppressDiagnosticsCodeFixProvider.cs | 3 +- ...stitutableMemberArgumentMatcherAnalyzer.cs | 21 +- ...SubstitutableMemberArgumentMatcherTests.cs | 2 +- 8 files changed, 97 insertions(+), 163 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index f8a8ef38..574fc10b 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -10,5 +10,6 @@ namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; internal sealed class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider : AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider { - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = NonSubstitutableMemberArgumentMatcherAnalyzer.MaybeAllowedAncestors; + // TODO + protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = ImmutableHashSet.Empty; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs index c7be090c..e61f5968 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -1,34 +1,14 @@ -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 NonSubstitutableMemberArgumentMatcherAnalyzer : AbstractNonSubstitutableMemberArgumentMatcherAnalyzer +internal sealed class NonSubstitutableMemberArgumentMatcherAnalyzer : AbstractNonSubstitutableMemberArgumentMatcherAnalyzer { - internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.InvocationExpression, - (int)SyntaxKind.ElementAccessExpression, - (int)SyntaxKind.AddAssignmentExpression, - (int)SyntaxKind.ObjectCreationExpression, - (int)SyntaxKind.SimpleAssignmentExpression); - - private static ImmutableHashSet IgnoredAncestors { get; } = - ImmutableHashSet.Create( - (int)SyntaxKind.VariableDeclarator); - public NonSubstitutableMemberArgumentMatcherAnalyzer() : base(NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance) { } - - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = MaybeAllowedAncestors; - - protected override ImmutableHashSet IgnoredArgMatcherAncestors { get; } = IgnoredAncestors; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs index c7c4c6a4..c915ae7f 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs @@ -100,6 +100,7 @@ private static ISymbol ExtractSymbol(IOperation operation) IInvocationOperation invocationOperation => invocationOperation.TargetMethod, IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), + IMemberReferenceOperation memberReferenceOperation => memberReferenceOperation.Member, _ => null }; return symbol; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs index ca30403b..0877e925 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -8,23 +8,22 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractNonSubstitutableMemberArgumentMatcherAnalyzer : AbstractDiagnosticAnalyzer - where TInvocationExpressionSyntax : SyntaxNode - where TSyntaxKind : struct, Enum +internal abstract class AbstractNonSubstitutableMemberArgumentMatcherAnalyzer : AbstractDiagnosticAnalyzer { - private readonly Action _analyzeInvocationAction; + internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( + OperationKind.Invocation, + OperationKind.BinaryOperator, + OperationKind.PropertyReference, + OperationKind.EventAssignment, + OperationKind.ObjectCreation, + OperationKind.SimpleAssignment); - private readonly INonSubstitutableMemberAnalysis _nonSubstitutableMemberAnalysis; - - private readonly int _invocationExpressionRawKind; - - private readonly int[] _parentInvocationSyntaxNodeHierarchy; + private static ImmutableHashSet IgnoredAncestors { get; } = + ImmutableHashSet.Create(OperationKind.VariableDeclarator, OperationKind.DynamicInvocation); - protected abstract ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } + private readonly Action _analyzeInvocationAction; - protected abstract ImmutableHashSet IgnoredArgMatcherAncestors { get; } - - protected abstract TSyntaxKind InvocationExpressionKind { get; } + private readonly INonSubstitutableMemberAnalysis _nonSubstitutableMemberAnalysis; protected AbstractNonSubstitutableMemberArgumentMatcherAnalyzer( INonSubstitutableMemberAnalysis nonSubstitutableMemberAnalysis, @@ -34,164 +33,115 @@ protected AbstractNonSubstitutableMemberArgumentMatcherAnalyzer( _nonSubstitutableMemberAnalysis = nonSubstitutableMemberAnalysis; _analyzeInvocationAction = AnalyzeInvocation; SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage); - _invocationExpressionRawKind = (int)Convert.ChangeType(InvocationExpressionKind, typeof(int)); - _parentInvocationSyntaxNodeHierarchy = new[] { _invocationExpressionRawKind }; } public override ImmutableArray SupportedDiagnostics { get; } protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext context) { - var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol is not IMethodSymbol methodSymbol) + if (context.Operation is not IInvocationOperation invocationOperation) { - return; + return; } - if (methodSymbol.IsArgMatcherLikeMethod() == false) + if (invocationOperation.TargetMethod.IsArgMatcherLikeMethod() == false) { return; } - AnalyzeArgLikeMethod(syntaxNodeContext, invocationExpression, methodSymbol); + AnalyzeArgLikeMethod(context, invocationOperation); } private void AnalyzeArgLikeMethod( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax argInvocationExpression, - IMethodSymbol invocationExpressionSymbol) + OperationAnalysisContext context, + IInvocationOperation invocationOperation) { - var enclosingExpression = FindMaybeAllowedEnclosingExpression(argInvocationExpression); + var enclosingOperation = FindMaybeAllowedEnclosingExpression(invocationOperation); // if Arg is used with not allowed expression, find if it is used in ignored ones eg. var x = Arg.Any // as variable might be used later on - if (enclosingExpression == null) + if (enclosingOperation == null) { - var ignoredEnclosingExpression = FindIgnoredEnclosingExpression(argInvocationExpression); + var ignoredEnclosingExpression = FindIgnoredEnclosingExpression(invocationOperation); if (ignoredEnclosingExpression == null) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocationExpression.GetLocation()); + invocationOperation.Syntax.GetLocation()); - syntaxNodeContext.ReportDiagnostic(diagnostic); + context.ReportDiagnostic(diagnostic); return; } } - if (enclosingExpression == null) + if (enclosingOperation == null) { return; } - var operation = syntaxNodeContext.SemanticModel.GetOperation(enclosingExpression); - - if (operation.IsEventAssignmentOperation()) + if (enclosingOperation.IsEventAssignmentOperation()) { return; } - var memberReferenceOperation = GetMemberReferenceOperation(operation); + var memberReferenceOperation = GetMemberReferenceOperation(enclosingOperation); if (AnalyzeEnclosingExpression( - syntaxNodeContext, - argInvocationExpression, - enclosingExpression, + context, + invocationOperation, + enclosingOperation, memberReferenceOperation)) { return; } AnalyzeAssignment( - syntaxNodeContext, - argInvocationExpression, - invocationExpressionSymbol, + context, + invocationOperation, memberReferenceOperation); } private bool AnalyzeEnclosingExpression( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax argInvocationExpression, - SyntaxNode enclosingExpression, + OperationAnalysisContext context, + IInvocationOperation argInvocation, + IOperation enclosingOperation, IMemberReferenceOperation memberReferenceOperation) { - var enclosingExpressionSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(enclosingExpression); - var enclosingExpressionSymbol = memberReferenceOperation?.Member ?? - enclosingExpressionSymbolInfo.Symbol; + var enclosingExpressionSymbol = memberReferenceOperation?.Member ?? enclosingOperation.ExtractSymbol(); if (enclosingExpressionSymbol == null) { - return AnalyzeEnclosingExpressionCandidateSymbols( - syntaxNodeContext, - argInvocationExpression, - enclosingExpression, - enclosingExpressionSymbolInfo); + var diagnostic = Diagnostic.Create( + DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, + argInvocation.Syntax.GetLocation()); + + context.TryReportDiagnostic(diagnostic, null); + return true; } - if (_nonSubstitutableMemberAnalysis.Analyze( - syntaxNodeContext, - enclosingExpression, - enclosingExpressionSymbol).CanBeSubstituted != false) + if (_nonSubstitutableMemberAnalysis.Analyze(memberReferenceOperation ?? enclosingOperation).CanBeSubstituted) { return false; } - syntaxNodeContext.TryReportDiagnostic( + context.TryReportDiagnostic( Diagnostic.Create( DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocationExpression.GetLocation()), + argInvocation.Syntax.GetLocation()), enclosingExpressionSymbol); return true; } - private bool AnalyzeEnclosingExpressionCandidateSymbols( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax argInvocationExpression, - SyntaxNode enclosingExpression, - SymbolInfo enclosingExpressionSymbolInfo) - { - if (enclosingExpressionSymbolInfo.CandidateSymbols.Length == 0) - { - var diagnostic = Diagnostic.Create( - DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocationExpression.GetLocation()); - - syntaxNodeContext.TryReportDiagnostic(diagnostic, null); - return true; - } - - foreach (var candidateSymbol in enclosingExpressionSymbolInfo.CandidateSymbols) - { - if (_nonSubstitutableMemberAnalysis.Analyze( - syntaxNodeContext, - enclosingExpression, - candidateSymbol).CanBeSubstituted == false) - { - var diagnostic = Diagnostic.Create( - DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocationExpression.GetLocation()); - - syntaxNodeContext.TryReportDiagnostic(diagnostic, candidateSymbol); - return true; - } - } - - return false; - } - private void AnalyzeAssignment( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax argInvocationExpression, - IMethodSymbol argInvocationExpressionSymbol, + OperationAnalysisContext context, + IInvocationOperation invocationOperation, IMemberReferenceOperation memberReferenceOperation) { if (memberReferenceOperation == null) @@ -199,42 +149,46 @@ private void AnalyzeAssignment( return; } - var syntaxNode = memberReferenceOperation.Syntax; - - if (IsWithinWhenLikeMethod(syntaxNodeContext, syntaxNode)) + if (IsWithinWhenLikeMethod(memberReferenceOperation)) { return; } - if (argInvocationExpressionSymbol.IsArgDoLikeMethod()) + if (invocationOperation.TargetMethod.IsArgDoLikeMethod()) { return; } - if (IsPrecededByReceivedLikeMethod(syntaxNodeContext, syntaxNode)) + if (IsPrecededByReceivedLikeMethod(memberReferenceOperation)) { return; } var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocationExpression.GetLocation()); + invocationOperation.Syntax.GetLocation()); - syntaxNodeContext.TryReportDiagnostic(diagnostic, memberReferenceOperation.Member); + context.TryReportDiagnostic(diagnostic, memberReferenceOperation.Member); } - private bool IsPrecededByReceivedLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode) + private bool IsPrecededByReceivedLikeMethod(IOperation operation) { - var parentInvocationSyntaxNode = syntaxNode.GetParentNode(_parentInvocationSyntaxNodeHierarchy); - return parentInvocationSyntaxNode != null && - syntaxNodeContext.SemanticModel.GetSymbolInfo(parentInvocationSyntaxNode).Symbol.IsReceivedLikeMethod(); + var substituteOperation = operation switch + { + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.GetSubstituteOperation(), + IInvocationOperation invocationOperation => invocationOperation.GetSubstituteOperation(), + _=> null + }; + + return substituteOperation.ExtractSymbol()?.IsReceivedLikeMethod() ?? false; } - private bool IsWithinWhenLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntaxNode) + private bool IsWithinWhenLikeMethod(IOperation operation) { - var invocation = syntaxNode.Ancestors().FirstOrDefault(ancestor => ancestor.RawKind == _invocationExpressionRawKind); + var invocation = operation.Ancestors().FirstOrDefault(ancestor => ancestor.Kind == OperationKind.Invocation); - return invocation != null && syntaxNodeContext.SemanticModel.GetSymbolInfo(invocation).Symbol.IsWhenLikeMethod(); + return invocation is IInvocationOperation invocationOperation && + invocationOperation.TargetMethod.IsWhenLikeMethod(); } private static IMemberReferenceOperation GetMemberReferenceOperation(IOperation operation) @@ -253,15 +207,15 @@ private static IMemberReferenceOperation GetMemberReferenceOperation(IOperation }; } - private SyntaxNode FindMaybeAllowedEnclosingExpression(TInvocationExpressionSyntax invocationExpression) => - FindEnclosingExpression(invocationExpression, MaybeAllowedArgMatcherAncestors); + private IOperation FindMaybeAllowedEnclosingExpression(IOperation operation) => + FindEnclosingExpression(operation, MaybeAllowedAncestors); - private SyntaxNode FindIgnoredEnclosingExpression(TInvocationExpressionSyntax invocationExpressionSyntax) => - FindEnclosingExpression(invocationExpressionSyntax, IgnoredArgMatcherAncestors); + private IOperation FindIgnoredEnclosingExpression(IOperation operation) => + FindEnclosingExpression(operation, IgnoredAncestors); - private static SyntaxNode FindEnclosingExpression(TInvocationExpressionSyntax invocationExpression, ImmutableHashSet ancestors) + private static IOperation FindEnclosingExpression(IOperation operation, ImmutableHashSet ancestors) { - return invocationExpression.Ancestors() - .FirstOrDefault(ancestor => ancestors.Contains(ancestor.RawKind)); + return operation.Ancestors() + .FirstOrDefault(ancestor => ancestors.Contains(ancestor.Kind)); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 02965dbc..92f77e7c 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; @@ -19,6 +20,9 @@ public static bool IsEventAssignmentOperation(this IOperation operation) }; } + public static IOperation GetSubstituteOperation(this IPropertyReferenceOperation propertyReferenceOperation) => + propertyReferenceOperation.Instance; + public static IOperation GetSubstituteOperation(this IInvocationOperation invocationOperation) { if (invocationOperation.Instance != null) @@ -109,6 +113,18 @@ public static IEnumerable Ancestors(this IOperation operation) } } + public static ISymbol ExtractSymbol(this IOperation operation) + { + var symbol = operation switch + { + IInvocationOperation invocationOperation => invocationOperation.TargetMethod, + IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, + IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), + _ => null + }; + return symbol; + } + private static bool IsImplicitlyProvidedArrayWithoutValues(IArgumentOperation arg) { return arg.IsImplicit && diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index 3a7c407b..8ee2fc9d 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -9,5 +9,6 @@ namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] internal sealed class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider : AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider { - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = NonSubstitutableMemberArgumentMatcherAnalyzer.MaybeAllowedAncestors; + // TODO + protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = ImmutableHashSet.Empty; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs index 62082071..12bf753a 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -1,33 +1,14 @@ -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 sealed class NonSubstitutableMemberArgumentMatcherAnalyzer : AbstractNonSubstitutableMemberArgumentMatcherAnalyzer +internal sealed class NonSubstitutableMemberArgumentMatcherAnalyzer : AbstractNonSubstitutableMemberArgumentMatcherAnalyzer { - internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.InvocationExpression, - (int)SyntaxKind.AddHandlerStatement, - (int)SyntaxKind.ObjectCreationExpression, - (int)SyntaxKind.EqualsExpression, - (int)SyntaxKind.SimpleAssignmentStatement); - - private static ImmutableHashSet IgnoredAncestors { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.VariableDeclarator); - public NonSubstitutableMemberArgumentMatcherAnalyzer() : base(NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance) { } - - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = MaybeAllowedAncestors; - - protected override ImmutableHashSet IgnoredArgMatcherAncestors { get; } = IgnoredAncestors; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs index 13c2a394..0c3461d9 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs @@ -911,7 +911,7 @@ End Class public override async Task ReportsNoDiagnostic_WhenOverloadCannotBeInferred() { - var source = $@"Imports System + var source = @"Imports System Imports NSubstitute Namespace MyNamespace From aa548361fbf541fe2b8f1648f4be37b7bc579425 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sat, 23 Jul 2022 16:21:41 +0200 Subject: [PATCH 12/35] GH-153 - using operations api in NonSubstitutableMemberAnalysis --- .../NonSubstitutableMemberAnalysis.cs | 18 --------- .../INonSubstitutableMemberAnalysis.cs | 6 --- ...s.cs => NonSubstitutableMemberAnalysis.cs} | 40 ++++++++----------- .../NonSubstitutableMemberAnalysis.cs | 18 --------- 4 files changed, 16 insertions(+), 66 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractNonSubstitutableMemberAnalysis.cs => NonSubstitutableMemberAnalysis.cs} (66%) delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs deleted file mode 100644 index 4fff9cdc..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; - -internal class NonSubstitutableMemberAnalysis : AbstractNonSubstitutableMemberAnalysis -{ - public static NonSubstitutableMemberAnalysis Instance { get; } = new (); - - private NonSubstitutableMemberAnalysis() - { - } - - protected override ImmutableHashSet KnownNonVirtualSyntaxKinds { get; } = ImmutableHashSet.Create( - typeof(LiteralExpressionSyntax)); -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs index 24aeeed7..663d1a0d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/INonSubstitutableMemberAnalysis.cs @@ -1,14 +1,8 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface INonSubstitutableMemberAnalysis { - NonSubstitutableMemberAnalysisResult Analyze( - in SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode accessedMember, - ISymbol symbol = null); - NonSubstitutableMemberAnalysisResult Analyze(IOperation operation); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs similarity index 66% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs index c915ae7f..afb3104a 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs @@ -1,50 +1,42 @@ -using System; 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 AbstractNonSubstitutableMemberAnalysis : INonSubstitutableMemberAnalysis +internal class NonSubstitutableMemberAnalysis : INonSubstitutableMemberAnalysis { - protected abstract ImmutableHashSet KnownNonVirtualSyntaxKinds { get; } + public static readonly INonSubstitutableMemberAnalysis Instance = new NonSubstitutableMemberAnalysis(); - public NonSubstitutableMemberAnalysisResult Analyze( - in SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode accessedMember, - ISymbol symbol = null) => - Analyze(accessedMember, symbol ?? syntaxNodeContext.SemanticModel.GetSymbolInfo(accessedMember).Symbol); + private static readonly ImmutableHashSet KnownNonVirtualOperationKinds = + ImmutableHashSet.Create(OperationKind.Literal); public NonSubstitutableMemberAnalysisResult Analyze(IOperation operation) { var symbol = ExtractSymbol(operation); - return Analyze(operation.Syntax, symbol); + return Analyze(operation, symbol); } private bool CanBeSubstituted( - SyntaxNode accessedMember, - ISymbol symbol) - { - return !KnownNonVirtualSyntaxKinds.Contains(accessedMember.GetType()) && - CanBeSubstituted(symbol); - } + IOperation operation, + ISymbol symbol) => + !KnownNonVirtualOperationKinds.Contains(operation.Kind) && CanBeSubstituted(symbol); - private NonSubstitutableMemberAnalysisResult Analyze(SyntaxNode accessedMember, ISymbol symbol) + private NonSubstitutableMemberAnalysisResult Analyze(IOperation operation, ISymbol symbol) { if (symbol == null) { return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: KnownNonVirtualSyntaxKinds.Contains(accessedMember.GetType()), + nonVirtualMemberSubstitution: KnownNonVirtualOperationKinds.Contains(operation.Kind), internalMemberSubstitution: false, symbol: null, - member: accessedMember, - memberName: accessedMember.ToString()); + member: operation.Syntax, + memberName: operation.ToString()); } - var canBeSubstituted = CanBeSubstituted(accessedMember, symbol); + var canBeSubstituted = CanBeSubstituted(operation, symbol); if (canBeSubstituted == false) { @@ -52,7 +44,7 @@ private NonSubstitutableMemberAnalysisResult Analyze(SyntaxNode accessedMember, nonVirtualMemberSubstitution: true, internalMemberSubstitution: false, symbol: symbol, - member: accessedMember, + member: operation.Syntax, memberName: symbol.Name); } @@ -62,7 +54,7 @@ private NonSubstitutableMemberAnalysisResult Analyze(SyntaxNode accessedMember, nonVirtualMemberSubstitution: false, internalMemberSubstitution: true, symbol: symbol, - member: accessedMember, + member: operation.Syntax, memberName: symbol.Name); } @@ -70,7 +62,7 @@ private NonSubstitutableMemberAnalysisResult Analyze(SyntaxNode accessedMember, nonVirtualMemberSubstitution: false, internalMemberSubstitution: false, symbol: symbol, - member: accessedMember, + member: operation.Syntax, memberName: symbol.Name); } diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs deleted file mode 100644 index c370ad9f..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal sealed class NonSubstitutableMemberAnalysis : AbstractNonSubstitutableMemberAnalysis -{ - public static NonSubstitutableMemberAnalysis Instance { get; } = new (); - - private NonSubstitutableMemberAnalysis() - { - } - - protected override ImmutableHashSet KnownNonVirtualSyntaxKinds { get; } = ImmutableHashSet.Create( - typeof(LiteralExpressionSyntax)); -} \ No newline at end of file From c308f1b39d72ccea6b7b86a26d18e7e341e21330 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sat, 23 Jul 2022 22:04:38 +0200 Subject: [PATCH 13/35] GH-153 - using operations api in NonSubstitutableMemberArgumentMatcherAnalyzer - further fixes --- ...tcherSuppressDiagnosticsCodeFixProvider.cs | 4 -- ...tcherSuppressDiagnosticsCodeFixProvider.cs | 21 ++++-- ...stitutableMemberArgumentMatcherAnalyzer.cs | 53 ++++++++------ .../NonSubstitutableMemberAnalysis.cs | 13 +++- ...tcherSuppressDiagnosticsCodeFixProvider.cs | 4 -- ...rSuppressDiagnosticsCodeFixActionsTests.cs | 72 +++++++++---------- ...rSuppressDiagnosticsCodeFixActionsTests.cs | 2 +- 7 files changed, 94 insertions(+), 75 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index 574fc10b..4e104016 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -1,7 +1,5 @@ -using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; -using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; using NSubstitute.Analyzers.Shared.CodeFixProviders; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; @@ -10,6 +8,4 @@ namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; internal sealed class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider : AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider { - // TODO - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = ImmutableHashSet.Empty; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index 8a621e3d..4347603a 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -2,6 +2,9 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.CodeFixProviders; @@ -9,23 +12,27 @@ internal abstract class AbstractNonSubstitutableMemberArgumentMatcherSuppressDia { public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.NonSubstitutableMemberArgumentMatcherUsage); - protected abstract ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } - protected override IEnumerable GetSuppressibleSymbol(SemanticModel model, SyntaxNode syntaxNode, ISymbol symbol) { - var ancestorNode = syntaxNode.Ancestors() - .FirstOrDefault(ancestor => MaybeAllowedArgMatcherAncestors.Contains(ancestor.RawKind)); + var operation = model.GetOperation(syntaxNode); + if (operation == null) + { + return Enumerable.Empty(); + } + + var ancestorOperation = operation.Ancestors() + .FirstOrDefault(ancestor => AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.MaybeAllowedAncestors.Contains(ancestor.Kind)); - if (ancestorNode == null) + if (ancestorOperation == null) { return Enumerable.Empty(); } - if (model.GetSymbolInfo(ancestorNode).Symbol is IMethodSymbol methodSymbol && methodSymbol.MethodKind == MethodKind.Constructor) + if (ancestorOperation is IInvocationOperation invocationOperation && invocationOperation.TargetMethod.MethodKind == MethodKind.Constructor) { return Enumerable.Empty(); } - return base.GetSuppressibleSymbol(model, ancestorNode, model.GetSymbolInfo(ancestorNode).Symbol); + return base.GetSuppressibleSymbol(model, ancestorOperation.Syntax, ancestorOperation.ExtractSymbol()); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs index 0877e925..0bea1753 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -13,13 +13,17 @@ internal abstract class AbstractNonSubstitutableMemberArgumentMatcherAnalyzer : internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( OperationKind.Invocation, OperationKind.BinaryOperator, + OperationKind.DynamicInvocation, OperationKind.PropertyReference, OperationKind.EventAssignment, OperationKind.ObjectCreation, OperationKind.SimpleAssignment); - private static ImmutableHashSet IgnoredAncestors { get; } = - ImmutableHashSet.Create(OperationKind.VariableDeclarator, OperationKind.DynamicInvocation); + private static readonly ImmutableHashSet IgnoredAncestors = + ImmutableHashSet.Create(OperationKind.VariableDeclarator, OperationKind.VariableDeclaration); + + private static readonly ImmutableHashSet DynamicOperations = + ImmutableHashSet.Create(OperationKind.DynamicInvocation, OperationKind.DynamicIndexerAccess, OperationKind.DynamicMemberReference); private readonly Action _analyzeInvocationAction; @@ -63,6 +67,11 @@ private void AnalyzeArgLikeMethod( { var enclosingOperation = FindMaybeAllowedEnclosingExpression(invocationOperation); + if (enclosingOperation != null && DynamicOperations.Contains(enclosingOperation.Kind)) + { + return; + } + // if Arg is used with not allowed expression, find if it is used in ignored ones eg. var x = Arg.Any // as variable might be used later on if (enclosingOperation == null) @@ -101,10 +110,13 @@ private void AnalyzeArgLikeMethod( return; } - AnalyzeAssignment( - context, - invocationOperation, - memberReferenceOperation); + if (memberReferenceOperation != null) + { + AnalyzeAssignment( + context, + invocationOperation, + memberReferenceOperation); + } } private bool AnalyzeEnclosingExpression( @@ -117,11 +129,7 @@ private bool AnalyzeEnclosingExpression( if (enclosingExpressionSymbol == null) { - var diagnostic = Diagnostic.Create( - DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocation.Syntax.GetLocation()); - - context.TryReportDiagnostic(diagnostic, null); + TryReportDiagnostic(context, argInvocation, null); return true; } @@ -130,11 +138,7 @@ private bool AnalyzeEnclosingExpression( return false; } - context.TryReportDiagnostic( - Diagnostic.Create( - DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, - argInvocation.Syntax.GetLocation()), - enclosingExpressionSymbol); + TryReportDiagnostic(context, argInvocation, enclosingExpressionSymbol); return true; } @@ -144,11 +148,6 @@ private void AnalyzeAssignment( IInvocationOperation invocationOperation, IMemberReferenceOperation memberReferenceOperation) { - if (memberReferenceOperation == null) - { - return; - } - if (IsWithinWhenLikeMethod(memberReferenceOperation)) { return; @@ -218,4 +217,16 @@ private static IOperation FindEnclosingExpression(IOperation operation, Immutabl return operation.Ancestors() .FirstOrDefault(ancestor => ancestors.Contains(ancestor.Kind)); } + + private void TryReportDiagnostic( + OperationAnalysisContext context, + IInvocationOperation argInvocation, + ISymbol enclosingExpressionSymbol) + { + context.TryReportDiagnostic( + Diagnostic.Create( + DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage, + argInvocation.Syntax.GetLocation()), + enclosingExpressionSymbol); + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs index afb3104a..5092d2bd 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs @@ -29,11 +29,11 @@ private NonSubstitutableMemberAnalysisResult Analyze(IOperation operation, ISymb if (symbol == null) { return new NonSubstitutableMemberAnalysisResult( - nonVirtualMemberSubstitution: KnownNonVirtualOperationKinds.Contains(operation.Kind), + nonVirtualMemberSubstitution: KnownNonVirtualOperationKinds.Contains(ExtractActualOperation(operation).Kind), internalMemberSubstitution: false, symbol: null, member: operation.Syntax, - memberName: operation.ToString()); + memberName: operation.Syntax.ToString()); } var canBeSubstituted = CanBeSubstituted(operation, symbol); @@ -97,4 +97,13 @@ private static ISymbol ExtractSymbol(IOperation operation) }; return symbol; } + + private static IOperation ExtractActualOperation(IOperation operation) + { + return operation switch + { + IConversionOperation conversionOperation => conversionOperation.Operand, + _ => operation + }; + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index 8ee2fc9d..d6989556 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -1,14 +1,10 @@ -using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using NSubstitute.Analyzers.Shared.CodeFixProviders; -using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] internal sealed class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider : AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider { - // TODO - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = ImmutableHashSet.Empty; } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs index d6771620..a1f9c5b8 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs @@ -19,25 +19,25 @@ public class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActi [Fact] public async Task CreatesCorrectCodeFixActions_ForIndexer() { - var source = $@"using System; + var source = @"using System; using NSubstitute; namespace MyNamespace -{{ +{ public class Foo - {{ + { public int this[int? firstArg] => 2; - }} + } public class FooTests - {{ + { public void Test() - {{ + { var substitute = Substitute.For(); _ = substitute[Arg.Any()]; - }} - }} -}}"; + } + } +}"; await VerifyCodeActions(source, new[] { $"Suppress {DiagnosticIdentifiers.NonSubstitutableMemberArgumentMatcherUsage} for indexer this[] in nsubstitute.json", @@ -49,27 +49,27 @@ await VerifyCodeActions(source, new[] [Fact] public async Task CreatesCorrectCodeFixActions_ForMethod() { - var source = $@"using System; + var source = @"using System; using NSubstitute; namespace MyNamespace -{{ +{ public class Foo - {{ + { public static int Bar(int? firstArg) - {{ + { return 2; - }} - }} + } + } public class FooTests - {{ + { public void Test() - {{ + { Foo.Bar(Arg.Any()); - }} - }} -}}"; + } + } +}"; await VerifyCodeActions(source, new[] { $"Suppress {DiagnosticIdentifiers.NonSubstitutableMemberArgumentMatcherUsage} for method Bar in nsubstitute.json", @@ -81,42 +81,42 @@ await VerifyCodeActions(source, new[] [Fact] public async Task DoesNotCreateCodeFixActions_WhenArgMatchesIsUsedInStandaloneExpression() { - var source = $@"using System; + var source = @"using System; using NSubstitute; namespace MyNamespace -{{ +{ public class FooTests - {{ + { public void Test() - {{ + { Arg.Any(); - }} - }} -}}"; + } + } +}"; await VerifyCodeActions(source, Array.Empty()); } [Fact] public async Task DoesNotCreateCodeFixActions_WhenArgMatchesIsUsedInConstructor() { - var source = $@"using System; + var source = @"using System; using NSubstitute; namespace MyNamespace -{{ +{ public class FooTests - {{ + { public FooTests(int firstArg) - {{ - }} + { + } public void Test() - {{ + { new FooTests(Arg.Any()); - }} - }} -}}"; + } + } +}"; await VerifyCodeActions(source, Array.Empty()); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs index 5e76faf4..324f1217 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixActionsTests.cs @@ -84,7 +84,7 @@ await VerifyCodeActions(source, new[] [Fact] public async Task DoesNotCreateCodeFixActions_WhenArgMatchesIsUsedInStandaloneExpression() { - var source = $@"Imports System + var source = @"Imports System Imports NSubstitute Namespace MyNamespace From 12659623c99b4e889fb6cb8ff562997b83d223b8 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 24 Jul 2022 18:35:22 +0200 Subject: [PATCH 14/35] GH-153 - using operations api in ReEntrantSetupAnalyzer --- .../ReEntrantCallFinder.cs | 39 +---- .../ReEntrantSetupAnalyzer.cs | 23 +-- .../AbstractCallInfoFinder.cs | 6 - .../AbstractDiagnosticAnalyzer.cs | 3 +- .../AbstractReEntrantCallFinder.cs | 142 +++++++++++++----- .../AbstractReEntrantSetupAnalyzer.cs | 99 ++++++------ .../IReEntrantCallFinder.cs | 6 +- .../Extensions/IOperationExtensions.cs | 1 + .../ReEntrantCallFinder.cs | 31 ---- .../ReEntrantSetupAnalyzer.cs | 23 +-- 10 files changed, 169 insertions(+), 204 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs index b32a55f8..a9a57a15 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -17,39 +17,12 @@ private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) { } - protected override ImmutableList GetReEntrantSymbols(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode) - { - var visitor = new ReEntrantCallVisitor(this, compilation, semanticModel, originatingExpression); - visitor.Visit(rootNode); - return visitor.InvocationSymbols; - } - - protected override IEnumerable GetPotentialOtherSubstituteInvocations(IEnumerable nodes) - { - foreach (var node in nodes) - { - switch (node) - { - case InvocationExpressionSyntax invocationExpressionSyntax: - yield return invocationExpressionSyntax; - break; - case ExpressionStatementSyntax expressionStatementSyntax when expressionStatementSyntax.Expression is InvocationExpressionSyntax invocationExpressionSyntax: - yield return invocationExpressionSyntax; - break; - case ConstructorDeclarationSyntax constructorDeclarationSyntax: - foreach (var potentialPreviousReturnsLikeInvocation in - GetPotentialOtherSubstituteInvocations( - constructorDeclarationSyntax.Body?.ChildNodes() ?? - constructorDeclarationSyntax.ExpressionBody?.ChildNodes())) - { - yield return potentialPreviousReturnsLikeInvocation; - } - - break; - } - } - } - + // protected override ImmutableList GetReEntrantSymbols(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode) + // { + // var visitor = new ReEntrantCallVisitor(this, compilation, semanticModel, originatingExpression); + // visitor.Visit(rootNode); + // return visitor.InvocationSymbols; + // } private class ReEntrantCallVisitor : CSharpSyntaxWalker { private readonly ReEntrantCallFinder _reEntrantCallFinder; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs index 653b1a78..a03b9b93 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs @@ -1,35 +1,14 @@ -using System.Collections.Generic; 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; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal sealed class ReEntrantSetupAnalyzer : AbstractReEntrantSetupAnalyzer +internal sealed class ReEntrantSetupAnalyzer : AbstractReEntrantSetupAnalyzer { public ReEntrantSetupAnalyzer() : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, ReEntrantCallFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override IEnumerable GetExpressionsFromArrayInitializer(ArgumentSyntax syntaxNode) - { - return syntaxNode.Expression.GetParameterExpressionsFromArrayArgument(); - } - - protected override IEnumerable GetArguments(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList.Arguments; - } - - protected override SyntaxNode GetArgumentExpression(ArgumentSyntax argumentSyntax) - { - return argumentSyntax.Expression; - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs index 56710912..8489cb37 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs @@ -62,12 +62,6 @@ private static bool HasMatchingParameterReference( parameterReferenceOperation.Parameter.Equals(callInfoParameterSymbol); } - private static IParameterReferenceOperation FindMatchingParameterReference(SemanticModel semanticModel, SyntaxNode syntaxNode) - { - var operation = semanticModel.GetOperation(syntaxNode); - return FindMatchingParameterReference(operation); - } - private static IParameterReferenceOperation FindMatchingParameterReference(IOperation operation) { var parameterReferenceOperation = operation switch diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs index 05f687bf..5c646601 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs @@ -13,7 +13,8 @@ protected AbstractDiagnosticAnalyzer(IDiagnosticDescriptorsProvider diagnosticDe public sealed override void Initialize(AnalysisContext context) { - context.EnableConcurrentExecution(); + // TODO restore + // context.EnableConcurrentExecution(); InitializeAnalyzer(context); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs index d91a632a..47ef4258 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractReEntrantCallFinder : IReEntrantCallFinder +internal abstract class + AbstractReEntrantCallFinder : IReEntrantCallFinder where TInvocationExpressionSyntax : SyntaxNode where TIdentifierExpressionSyntax : SyntaxNode { @@ -18,24 +20,32 @@ protected AbstractReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFi _substitutionNodeFinder = substitutionNodeFinder; } - public ImmutableList GetReEntrantCalls(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode) + public ImmutableList GetReEntrantCalls(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) { - var symbolInfo = semanticModel.GetSymbolInfo(rootNode); + var rootNodeSymbol = rootNode.ExtractSymbol(); - if (symbolInfo.Symbol.IsLocal() || semanticModel.GetTypeInfo(rootNode).IsCallInfoDelegate(semanticModel.Compilation)) + if (rootNodeSymbol == null || rootNode.Kind == OperationKind.LocalReference) { - return ImmutableList.Empty; + return ImmutableList.Empty; } - var reEntrantSymbols = GetReEntrantSymbols(compilation, semanticModel, originatingExpression, rootNode); - var otherSubstitutions = GetOtherSubstitutionsForSymbol(semanticModel, rootNode, symbolInfo.Symbol); + var reEntrantSymbols = GetReEntrantSymbols(compilation, invocationOperation, rootNode); + var otherSubstitutions = GetOtherSubstitutionsForSymbol(compilation, rootNode, rootNodeSymbol); return reEntrantSymbols.AddRange(otherSubstitutions); } - protected abstract ImmutableList GetReEntrantSymbols(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode); - - protected abstract IEnumerable GetPotentialOtherSubstituteInvocations(IEnumerable nodes); + protected virtual IEnumerable GetPotentialOtherSubstituteInvocations(Compilation compilation, IEnumerable operations) + { + foreach (var operation in operations) + { + var visitor = new ReEntrantCallVisitor(compilation, operation); + foreach (var visitorInvocationOperation in visitor.InvocationOperations) + { + yield return visitorInvocationOperation; + } + } + } protected IEnumerable GetRelatedNodes(Compilation compilation, SemanticModel semanticModel, SyntaxNode syntaxNode) { @@ -76,35 +86,25 @@ protected bool IsInnerReEntryLikeMethod(SemanticModel semanticModel, ISymbol sym return symbol.IsInnerReEntryLikeMethod(); } - private IEnumerable GetOtherSubstitutionsForSymbol(SemanticModel semanticModel, SyntaxNode rootNode, ISymbol rootNodeSymbol) + private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol rootNodeSymbol) { if (rootNodeSymbol == null) { yield break; } - var rootIdentifierNode = GetIdentifierExpressionSyntax(rootNode); - if (rootIdentifierNode == null) - { - yield break; - } + var rootIdentifierNode = GetIdentifierOperation(rootOperation); - var rootIdentifierSymbol = semanticModel.GetSymbolInfo(rootIdentifierNode); + var rootIdentifierSymbol = rootIdentifierNode?.ExtractSymbol(); - if (rootIdentifierSymbol.Symbol == null) + if (rootIdentifierSymbol == null) { yield break; } - var ancestorChildNodes = rootNode.Ancestors().SelectMany(ancestor => ancestor.ChildNodes()); - foreach (var syntaxNode in GetPotentialOtherSubstituteInvocations(ancestorChildNodes)) + var ancestorChildNodes = rootOperation.Ancestors().SelectMany(ancestor => ancestor.Children); + foreach (var operation in GetPotentialOtherSubstituteInvocations(compilation, ancestorChildNodes)) { - var operation = semanticModel.GetOperation(syntaxNode) as IInvocationOperation; - if (operation == null) - { - continue; - } - if (operation.TargetMethod.IsReturnLikeMethod() == false) { continue; @@ -112,26 +112,98 @@ private IEnumerable GetOtherSubstitutionsForSymbol(SemanticModel semant var substitutedNode = _substitutionNodeFinder.FindForStandardExpression(operation); - // TODO extract from operation - var substituteNodeSymbol = semanticModel.GetSymbolInfo(substitutedNode.Syntax).Symbol; - if (!substituteNodeSymbol.Equals(rootNodeSymbol)) + var substituteNodeSymbol = substitutedNode?.ExtractSymbol(); + + if (substituteNodeSymbol == null) + { + continue; + } + + if (!rootNodeSymbol.Equals(substituteNodeSymbol)) { continue; } // TODO from operation - var substituteNodeIdentifier = GetIdentifierExpressionSyntax(substitutedNode.Syntax); + var substituteNodeIdentifier = GetIdentifierOperation(substitutedNode); - var substituteIdentifierSymbol = semanticModel.GetSymbolInfo(substituteNodeIdentifier); - if (rootIdentifierSymbol.Symbol.Equals(substituteIdentifierSymbol.Symbol)) + if (rootIdentifierSymbol.Equals(substituteNodeIdentifier.ExtractSymbol())) { - yield return substituteNodeSymbol; + // TODO + yield return substitutedNode as IInvocationOperation; } } } - private TIdentifierExpressionSyntax GetIdentifierExpressionSyntax(SyntaxNode node) + private ILocalReferenceOperation GetIdentifierOperation(IOperation node) { - return node.ChildNodes().FirstOrDefault() as TIdentifierExpressionSyntax; + // TODO can it be done better? + return node.Children.FirstOrDefault() as ILocalReferenceOperation; + } + + private ImmutableList GetReEntrantSymbols(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) + { + var reentryVisitor = new ReEntrantCallVisitor(compilation, invocationOperation); + reentryVisitor.Visit(rootNode); + + return reentryVisitor.InvocationOperations; + } + + private class ReEntrantCallVisitor : OperationWalker + { + private readonly Compilation _compilation; + private readonly HashSet _visitedOperations = new (); + private readonly List _invocationOperation = new (); + private readonly Dictionary _semanticModelCache = new (1); + + public ImmutableList InvocationOperations => _invocationOperation.ToImmutableList(); + + public ReEntrantCallVisitor(Compilation compilation, IOperation initialOperation) + { + _compilation = compilation; + _visitedOperations.Add(initialOperation); + } + + public override void VisitInvocation(IInvocationOperation operation) + { + if (_visitedOperations.Contains(operation) == false && operation.TargetMethod.IsInnerReEntryLikeMethod()) + { + _invocationOperation.Add(operation); + } + + VisitRelatedSymbols(operation); + base.VisitInvocation(operation); + } + + private void VisitRelatedSymbols(IInvocationOperation invocationOperation) + { + if (_visitedOperations.Contains(invocationOperation)) + { + return; + } + + _visitedOperations.Add(invocationOperation); + + foreach (var location in invocationOperation.TargetMethod.Locations.Where(location => location.IsInSource)) + { + var root = location.SourceTree.GetRoot(); + var relatedNode = root.FindNode(location.SourceSpan); + Visit(GetSemanticModel(relatedNode).GetOperation(relatedNode)); + } + } + + private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) + { + var syntaxTree = syntaxNode.SyntaxTree; + if (_semanticModelCache.TryGetValue(syntaxTree, out var semanticModel)) + { + return semanticModel; + } + + semanticModel = _compilation.GetSemanticModel(syntaxTree); + _semanticModelCache[syntaxTree] = semanticModel; + + return semanticModel; + } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index dd62109b..4d02f037 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -9,13 +9,10 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractReEntrantSetupAnalyzer : AbstractDiagnosticAnalyzer - where TSyntaxKind : struct - where TInvocationExpressionSyntax : SyntaxNode - where TArgumentSyntax : SyntaxNode +internal abstract class AbstractReEntrantSetupAnalyzer : AbstractDiagnosticAnalyzer { private readonly IReEntrantCallFinder _reEntrantCallFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; public override ImmutableArray SupportedDiagnostics { get; } @@ -29,96 +26,92 @@ protected AbstractReEntrantSetupAnalyzer( SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.ReEntrantSubstituteCall); } - protected abstract TSyntaxKind InvocationExpressionKind { get; } - protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - protected abstract IEnumerable GetExpressionsFromArrayInitializer(TArgumentSyntax syntaxNode); - - protected abstract IEnumerable GetArguments(TInvocationExpressionSyntax invocationExpressionSyntax); - - protected abstract SyntaxNode GetArgumentExpression(TArgumentSyntax argumentSyntax); - - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext context) { - var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) + if (context.Operation is not IInvocationOperation invocationOperation) { - return; + return; } - var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol; - - if (methodSymbol.IsInitialReEntryLikeMethod() == false) + if (invocationOperation.TargetMethod.IsInitialReEntryLikeMethod() == false) { - return; + return; } - var allArguments = GetArguments(invocationExpression); - var argumentsForAnalysis = methodSymbol.MethodKind == MethodKind.ReducedExtension ? allArguments : allArguments.Skip(1); + var argumentOperations = invocationOperation.GetOrderedArgumentOperationsWithoutInstanceArgument(); - foreach (var argument in argumentsForAnalysis) + foreach (var argumentOperation in argumentOperations) { - var operation = syntaxNodeContext.SemanticModel.GetOperation(argument) as IArgumentOperation; - - if (IsPassedByParamsArrayOfCallInfoFunc(syntaxNodeContext.SemanticModel.Compilation, operation)) + if (IsPassedByParamsArrayOfCallInfoFunc(context.Compilation, argumentOperation)) { continue; } - if (IsPassedByParamsArray(operation)) + if (IsPassedByParamsArray(argumentOperation)) { - AnalyzeParamsArgument(syntaxNodeContext, argument, invocationExpression, methodSymbol); + AnalyzeParamsArgument(context, argumentOperation, invocationOperation); } else { - AnalyzeExpression(syntaxNodeContext, GetArgumentExpression(argument), invocationExpression, methodSymbol); + AnalyzeExpression(context, argumentOperation.Value, invocationOperation); } } } private void AnalyzeParamsArgument( - SyntaxNodeAnalysisContext syntaxNodeContext, - TArgumentSyntax argument, - TInvocationExpressionSyntax invocationExpression, - IMethodSymbol methodSymbol) + OperationAnalysisContext context, + IArgumentOperation argumentOperation, + IInvocationOperation invocationOperation) { - var arrayInitializersExpressions = GetExpressionsFromArrayInitializer(argument); + var initializerOperations = GetOperationsFromArrayInitializer(argumentOperation); // if array elements can't be extracted, analyze argument itself - foreach (var argumentExpression in arrayInitializersExpressions ?? new[] { GetArgumentExpression(argument) }) + foreach (var operation in initializerOperations ?? new[] { argumentOperation.Value }) + { + AnalyzeExpression(context, operation, invocationOperation); + } + } + + private IEnumerable GetOperationsFromArrayInitializer(IArgumentOperation argumentOperation) + { + if (argumentOperation.Value is IArrayCreationOperation arrayCreationOperation) { - AnalyzeExpression(syntaxNodeContext, argumentExpression, invocationExpression, methodSymbol); + return arrayCreationOperation.Initializer.ElementValues; } + + if (argumentOperation.Value is IArrayInitializerOperation arrayInitializerOperation) + { + return arrayInitializerOperation.ElementValues; + } + + return null; } private void AnalyzeExpression( - SyntaxNodeAnalysisContext syntaxNodeContext, - SyntaxNode argumentExpression, - TInvocationExpressionSyntax invocationExpression, - IMethodSymbol methodSymbol) + OperationAnalysisContext context, + IOperation operation, + IInvocationOperation invocationOperation) { var reentrantSymbol = _reEntrantCallFinder.GetReEntrantCalls( - syntaxNodeContext.Compilation, - syntaxNodeContext.SemanticModel, - invocationExpression, - argumentExpression).FirstOrDefault(); + context.Compilation, + invocationOperation, + operation).FirstOrDefault(); if (reentrantSymbol != null) { var diagnostic = Diagnostic.Create( DiagnosticDescriptorsProvider.ReEntrantSubstituteCall, - argumentExpression.GetLocation(), - methodSymbol.Name, - reentrantSymbol.Name, - argumentExpression.ToString()); + operation.Syntax.GetLocation(), + invocationOperation.TargetMethod.Name, + reentrantSymbol.TargetMethod.Name, + operation.Syntax.ToString()); - syntaxNodeContext.ReportDiagnostic(diagnostic); + context.ReportDiagnostic(diagnostic); } } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs index 51a09536..ba478855 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs @@ -1,9 +1,13 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface IReEntrantCallFinder { - ImmutableList GetReEntrantCalls(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode); + ImmutableList GetReEntrantCalls( + Compilation compilation, + IInvocationOperation invocationOperation, + IOperation rootNode); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 92f77e7c..1e9d8d9c 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -120,6 +120,7 @@ public static ISymbol ExtractSymbol(this IOperation operation) IInvocationOperation invocationOperation => invocationOperation.TargetMethod, IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), + IAwaitOperation awaitOperation => ExtractSymbol(awaitOperation.Operation), _ => null }; return symbol; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 6107e044..ad6226b6 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -17,37 +17,6 @@ private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) { } - protected override ImmutableList GetReEntrantSymbols(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode) - { - var visitor = new ReEntrantCallVisitor(this, compilation, semanticModel); - visitor.Visit(rootNode); - return visitor.InvocationSymbols; - } - - protected override IEnumerable GetPotentialOtherSubstituteInvocations(IEnumerable nodes) - { - foreach (var node in nodes) - { - switch (node) - { - case InvocationExpressionSyntax invocationExpressionSyntax: - yield return invocationExpressionSyntax; - break; - case ExpressionStatementSyntax expressionStatementSyntax when expressionStatementSyntax.Expression is InvocationExpressionSyntax invocationExpressionSyntax: - yield return invocationExpressionSyntax; - break; - case ConstructorBlockSyntax constructorDeclarationSyntax: - foreach (var potentialPreviousReturnsLikeInvocation in GetPotentialOtherSubstituteInvocations( - constructorDeclarationSyntax.ChildNodes())) - { - yield return potentialPreviousReturnsLikeInvocation; - } - - break; - } - } - } - private class ReEntrantCallVisitor : VisualBasicSyntaxWalker { private readonly ReEntrantCallFinder _reEntrantCallFinder; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs index 04c171ab..67805be6 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantSetupAnalyzer.cs @@ -1,35 +1,14 @@ -using System.Collections.Generic; using Microsoft.CodeAnalysis; 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; [DiagnosticAnalyzer(LanguageNames.VisualBasic)] -internal sealed class ReEntrantSetupAnalyzer : AbstractReEntrantSetupAnalyzer +internal sealed class ReEntrantSetupAnalyzer : AbstractReEntrantSetupAnalyzer { public ReEntrantSetupAnalyzer() : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, ReEntrantCallFinder.Instance) { } - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; - - protected override IEnumerable GetExpressionsFromArrayInitializer(ArgumentSyntax syntaxNode) - { - return syntaxNode.GetExpression().GetParameterExpressionsFromArrayArgument(); - } - - protected override IEnumerable GetArguments(InvocationExpressionSyntax invocationExpressionSyntax) - { - return invocationExpressionSyntax.ArgumentList.Arguments; - } - - protected override SyntaxNode GetArgumentExpression(ArgumentSyntax argumentSyntax) - { - return argumentSyntax.GetExpression(); - } } \ No newline at end of file From ba58858e661741ca81c3bce561fcf52d27bdf362 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 14 Aug 2022 17:07:14 +0200 Subject: [PATCH 15/35] GH-153 - SyncOverAsyncThrowsCodeFixProvider fixes after merge --- .../SyncOverAsyncThrowsCodeFixProvider.cs | 13 +++++ .../ReEntrantCallFinder.cs | 2 +- ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 18 ++---- .../AbstractReEntrantCallFinder.cs | 58 +++++++++++-------- .../AbstractReEntrantSetupAnalyzer.cs | 30 +++++----- .../IReEntrantCallFinder.cs | 4 +- .../Extensions/IOperationExtensions.cs | 2 + .../SyncOverAsyncThrowsCodeFixProvider.cs | 15 +++++ .../ReEntrantCallFinder.cs | 2 +- 9 files changed, 89 insertions(+), 55 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs index af7fdb4a..54475582 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs @@ -1,7 +1,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; @@ -12,4 +15,14 @@ public SyncOverAsyncThrowsCodeFixProvider() : base(SubstitutionNodeFinder.Instance) { } + + protected override SyntaxNode UpdateMemberExpression(IInvocationOperation invocationOperation, SyntaxNode updatedNameSyntax) + { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; + var expressionSyntax = invocationExpressionSyntax.Expression; + return invocationExpressionSyntax.WithExpression(MemberAccessExpression( + expressionSyntax.Kind(), + ((MemberAccessExpressionSyntax)expressionSyntax).Expression, + (SimpleNameSyntax)updatedNameSyntax)); + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs index a9a57a15..bae37bcd 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; -internal class ReEntrantCallFinder : AbstractReEntrantCallFinder +internal class ReEntrantCallFinder : AbstractReEntrantCallFinder { public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 56a59803..2e3e1df7 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -62,7 +62,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix(codeAction, diagnostic); } - protected abstract SyntaxNode UpdateMemberExpression(SyntaxNode invocationExpressionSyntax, SyntaxNode updatedNameSyntax); + protected abstract SyntaxNode UpdateMemberExpression(IInvocationOperation invocationOperation, SyntaxNode updatedNameSyntax); private async Task CreateChangedDocument( CodeFixContext context, @@ -77,11 +77,10 @@ private async Task CreateChangedDocument( var updatedInvocationExpression = useModernSyntax ? await CreateThrowsAsyncInvocationExpression( - currentInvocationExpression, + invocationOperation, invocationSymbol, context) : await CreateReturnInvocationExpression( - currentInvocationExpression, invocationOperation, invocationSymbol, context); @@ -92,7 +91,7 @@ private async Task CreateChangedDocument( } private async Task CreateThrowsAsyncInvocationExpression( - SyntaxNode currentInvocationExpression, + IInvocationOperation invocationOperation, IMethodSymbol invocationSymbol, CodeFixContext context) { @@ -108,11 +107,10 @@ private async Task CreateThrowsAsyncInvocationExpression( ? syntaxGenerator.GenericName(updatedMethodName, invocationSymbol.TypeArguments) : syntaxGenerator.IdentifierName(updatedMethodName); - return UpdateMemberExpression(currentInvocationExpression, nameSyntax); + return UpdateMemberExpression(invocationOperation, nameSyntax); } private async Task CreateReturnInvocationExpression( - SyntaxNode currentInvocationExpression, IInvocationOperation invocationOperation, IMethodSymbol invocationSymbol, CodeFixContext context) @@ -129,7 +127,6 @@ private async Task CreateReturnInvocationExpression( if (invocationSymbol.MethodKind == MethodKind.Ordinary) { return CreateReturnOrdinalInvocationExpression( - currentInvocationExpression, invocationOperation, syntaxGenerator, fromExceptionInvocationExpression, @@ -137,7 +134,6 @@ private async Task CreateReturnInvocationExpression( } return CreateReturnExtensionInvocationExpression( - currentInvocationExpression, invocationOperation, syntaxGenerator, fromExceptionInvocationExpression, @@ -145,7 +141,6 @@ private async Task CreateReturnInvocationExpression( } private static SyntaxNode CreateReturnOrdinalInvocationExpression( - SyntaxNode currentInvocationExpression, IInvocationOperation invocationOperation, SyntaxGenerator syntaxGenerator, SyntaxNode fromExceptionInvocationExpression, @@ -155,11 +150,10 @@ private static SyntaxNode CreateReturnOrdinalInvocationExpression( syntaxGenerator.MemberAccessExpression( syntaxGenerator.DottedName("NSubstitute.SubstituteExtensions"), returnsMethodName), invocationOperation.Arguments.First(arg => arg.Parameter.Ordinal == 0).Value.Syntax, - fromExceptionInvocationExpression).WithTriviaFrom(currentInvocationExpression); + fromExceptionInvocationExpression).WithTriviaFrom(invocationOperation.Syntax); } private SyntaxNode CreateReturnExtensionInvocationExpression( - SyntaxNode currentInvocationExpression, IInvocationOperation invocationOperation, SyntaxGenerator syntaxGenerator, SyntaxNode fromExceptionInvocationExpression, @@ -171,7 +165,7 @@ private SyntaxNode CreateReturnExtensionInvocationExpression( syntaxGenerator.MemberAccessExpression(substituteNodeSyntax, returnsMethodName); return syntaxGenerator.InvocationExpression(accessExpression, fromExceptionInvocationExpression) - .WithTriviaFrom(currentInvocationExpression); + .WithTriviaFrom(invocationOperation.Syntax); } private static SyntaxNode CreateFromExceptionInvocationExpression( diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs index 47ef4258..5610884f 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs @@ -1,17 +1,15 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Linq; -using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.Extensions; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class - AbstractReEntrantCallFinder : IReEntrantCallFinder - where TInvocationExpressionSyntax : SyntaxNode - where TIdentifierExpressionSyntax : SyntaxNode +internal abstract class AbstractReEntrantCallFinder : IReEntrantCallFinder { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; @@ -20,19 +18,22 @@ protected AbstractReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFi _substitutionNodeFinder = substitutionNodeFinder; } - public ImmutableList GetReEntrantCalls(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) + public IReadOnlyList GetReEntrantCalls( + Compilation compilation, + IInvocationOperation invocationOperation, + IOperation rootNode) { var rootNodeSymbol = rootNode.ExtractSymbol(); if (rootNodeSymbol == null || rootNode.Kind == OperationKind.LocalReference) { - return ImmutableList.Empty; + return Array.Empty(); } var reEntrantSymbols = GetReEntrantSymbols(compilation, invocationOperation, rootNode); var otherSubstitutions = GetOtherSubstitutionsForSymbol(compilation, rootNode, rootNodeSymbol); - return reEntrantSymbols.AddRange(otherSubstitutions); + return reEntrantSymbols.Concat(otherSubstitutions).ToList().AsReadOnly(); } protected virtual IEnumerable GetPotentialOtherSubstituteInvocations(Compilation compilation, IEnumerable operations) @@ -40,6 +41,7 @@ protected virtual IEnumerable GetPotentialOtherSubstituteI foreach (var operation in operations) { var visitor = new ReEntrantCallVisitor(compilation, operation); + visitor.Visit(operation); foreach (var visitorInvocationOperation in visitor.InvocationOperations) { yield return visitorInvocationOperation; @@ -55,16 +57,18 @@ protected IEnumerable GetRelatedNodes(Compilation compilation, Seman } var symbol = GetSemanticModel(compilation, semanticModel, syntaxNode).GetSymbolInfo(syntaxNode); - if (symbol.Symbol != null && symbol.Symbol.IsLocal() == false && symbol.Symbol.Locations.Any()) + if (symbol.Symbol == null || symbol.Symbol.IsLocal() || symbol.Symbol.Locations.Length == 0) { - foreach (var symbolLocation in symbol.Symbol.Locations.Where(location => location.SourceTree != null)) + yield break; + } + + foreach (var symbolLocation in symbol.Symbol.Locations.Where(location => location.SourceTree != null)) + { + var root = symbolLocation.SourceTree.GetRoot(); + var relatedNode = root.FindNode(symbolLocation.SourceSpan); + if (relatedNode != null) { - var root = symbolLocation.SourceTree.GetRoot(); - var relatedNode = root.FindNode(symbolLocation.SourceSpan); - if (relatedNode != null) - { - yield return relatedNode; - } + yield return relatedNode; } } } @@ -86,14 +90,14 @@ protected bool IsInnerReEntryLikeMethod(SemanticModel semanticModel, ISymbol sym return symbol.IsInnerReEntryLikeMethod(); } - private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol rootNodeSymbol) + private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol rootNodeSymbol) { if (rootNodeSymbol == null) { yield break; } - var rootIdentifierNode = GetIdentifierOperation(rootOperation); + var rootIdentifierNode = GetLocalReferenceOperation(rootOperation); var rootIdentifierSymbol = rootIdentifierNode?.ExtractSymbol(); @@ -124,24 +128,28 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compila continue; } - // TODO from operation - var substituteNodeIdentifier = GetIdentifierOperation(substitutedNode); + var substituteNodeIdentifier = GetLocalReferenceOperation(substitutedNode); if (rootIdentifierSymbol.Equals(substituteNodeIdentifier.ExtractSymbol())) { - // TODO - yield return substitutedNode as IInvocationOperation; + yield return substitutedNode; } } } - private ILocalReferenceOperation GetIdentifierOperation(IOperation node) + private IOperation GetLocalReferenceOperation(IOperation node) { // TODO can it be done better? - return node.Children.FirstOrDefault() as ILocalReferenceOperation; + var child = node.Children.FirstOrDefault(); + return child switch + { + ILocalReferenceOperation _ => child, + IFieldReferenceOperation _ => child, + _ => null + }; } - private ImmutableList GetReEntrantSymbols(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) + private IEnumerable GetReEntrantSymbols(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) { var reentryVisitor = new ReEntrantCallVisitor(compilation, invocationOperation); reentryVisitor.Visit(rootNode); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index 4d02f037..b59a7bd7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -70,26 +70,28 @@ private void AnalyzeParamsArgument( { var initializerOperations = GetOperationsFromArrayInitializer(argumentOperation); - // if array elements can't be extracted, analyze argument itself - foreach (var operation in initializerOperations ?? new[] { argumentOperation.Value }) + if (initializerOperations != null) { - AnalyzeExpression(context, operation, invocationOperation); + foreach (var operation in initializerOperations) + { + AnalyzeExpression(context, operation, invocationOperation); + } + + return; } + + // if array elements can't be extracted, analyze argument itself + AnalyzeExpression(context, argumentOperation.Value, invocationOperation); } private IEnumerable GetOperationsFromArrayInitializer(IArgumentOperation argumentOperation) { - if (argumentOperation.Value is IArrayCreationOperation arrayCreationOperation) + return argumentOperation.Value switch { - return arrayCreationOperation.Initializer.ElementValues; - } - - if (argumentOperation.Value is IArrayInitializerOperation arrayInitializerOperation) - { - return arrayInitializerOperation.ElementValues; - } - - return null; + IArrayCreationOperation arrayCreationOperation => arrayCreationOperation.Initializer.ElementValues, + IArrayInitializerOperation arrayInitializerOperation => arrayInitializerOperation.ElementValues, + _ => null + }; } private void AnalyzeExpression( @@ -108,7 +110,7 @@ private void AnalyzeExpression( DiagnosticDescriptorsProvider.ReEntrantSubstituteCall, operation.Syntax.GetLocation(), invocationOperation.TargetMethod.Name, - reentrantSymbol.TargetMethod.Name, + reentrantSymbol.ExtractSymbol()?.Name ?? string.Empty, operation.Syntax.ToString()); context.ReportDiagnostic(diagnostic); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs index ba478855..5c9aa063 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/IReEntrantCallFinder.cs @@ -1,4 +1,4 @@ -using System.Collections.Immutable; +using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal interface IReEntrantCallFinder { - ImmutableList GetReEntrantCalls( + IReadOnlyList GetReEntrantCalls( Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode); diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 1e9d8d9c..7329bf64 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -121,6 +121,8 @@ public static ISymbol ExtractSymbol(this IOperation operation) IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), IAwaitOperation awaitOperation => ExtractSymbol(awaitOperation.Operation), + ILocalReferenceOperation localReferenceOperation => localReferenceOperation.Local, + IFieldReferenceOperation fieldReferenceOperation => fieldReferenceOperation.Field, _ => null }; return symbol; diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs index 2c397a31..6e05cd55 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SyncOverAsyncThrowsCodeFixProvider.cs @@ -1,7 +1,11 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; +using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; @@ -12,4 +16,15 @@ public SyncOverAsyncThrowsCodeFixProvider() : base(SubstitutionNodeFinder.Instance) { } + + protected override SyntaxNode UpdateMemberExpression(IInvocationOperation invocationOperation, SyntaxNode updatedNameSyntax) + { + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; + var expressionSyntax = invocationExpressionSyntax.Expression; + return invocationExpressionSyntax.WithExpression(MemberAccessExpression( + expressionSyntax.Kind(), + ((MemberAccessExpressionSyntax)expressionSyntax).Expression, + Token(SyntaxKind.DotToken), + (SimpleNameSyntax)updatedNameSyntax)); + } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs index ad6226b6..431cde57 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; -internal class ReEntrantCallFinder : AbstractReEntrantCallFinder +internal class ReEntrantCallFinder : AbstractReEntrantCallFinder { public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); From bbb3f7f37443fb951874d613893f228c5414e095 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Thu, 25 Aug 2022 02:27:04 +0200 Subject: [PATCH 16/35] GH-153 - using operations api in ReEntrantCallFinder --- .../ReEntrantCallFinder.cs | 146 ------------------ .../AbstractReEntrantCallFinder.cs | 85 ++++------ .../ReEntrantCallFinder.cs | 142 ----------------- .../DiagnosticAnalyzers/DiagnosticResult.cs | 59 ------- 4 files changed, 32 insertions(+), 400 deletions(-) delete mode 100644 tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticResult.cs diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs index bae37bcd..e77b6d89 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -1,9 +1,3 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; @@ -16,144 +10,4 @@ private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) : base(substitutionNodeFinder) { } - - // protected override ImmutableList GetReEntrantSymbols(Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression, SyntaxNode rootNode) - // { - // var visitor = new ReEntrantCallVisitor(this, compilation, semanticModel, originatingExpression); - // visitor.Visit(rootNode); - // return visitor.InvocationSymbols; - // } - private class ReEntrantCallVisitor : CSharpSyntaxWalker - { - private readonly ReEntrantCallFinder _reEntrantCallFinder; - private readonly Compilation _compilation; - private readonly SemanticModel _semanticModel; - private readonly HashSet _visitedNodes = new (); - private readonly List _invocationSymbols = new (); - - public ImmutableList InvocationSymbols => _invocationSymbols.ToImmutableList(); - - public ReEntrantCallVisitor(ReEntrantCallFinder reEntrantCallFinder, Compilation compilation, SemanticModel semanticModel, SyntaxNode originatingExpression) - { - _reEntrantCallFinder = reEntrantCallFinder; - _compilation = compilation; - _semanticModel = semanticModel; - _visitedNodes.Add(originatingExpression); - } - - public override void VisitInvocationExpression(InvocationExpressionSyntax node) - { - if (_visitedNodes.Contains(node) == false && _compilation.ContainsSyntaxTree(node.SyntaxTree)) - { - var semanticModel = _reEntrantCallFinder.GetSemanticModel(_compilation, _semanticModel, node); - var symbolInfo = semanticModel.GetSymbolInfo(node); - if (_reEntrantCallFinder.IsInnerReEntryLikeMethod(semanticModel, symbolInfo.Symbol)) - { - _invocationSymbols.Add(symbolInfo.Symbol); - } - } - - base.VisitInvocationExpression(node); - } - - public override void VisitClassDeclaration(ClassDeclarationSyntax node) - { - } - - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - } - - public override void VisitTrivia(SyntaxTrivia trivia) - { - } - - public override void VisitLeadingTrivia(SyntaxToken token) - { - } - - public override void VisitTrailingTrivia(SyntaxToken token) - { - } - - public override void VisitAttribute(AttributeSyntax node) - { - } - - public override void VisitAttributeArgument(AttributeArgumentSyntax node) - { - } - - public override void VisitAttributeArgumentList(AttributeArgumentListSyntax node) - { - } - - public override void VisitAttributeList(AttributeListSyntax node) - { - } - - public override void VisitAttributeTargetSpecifier(AttributeTargetSpecifierSyntax node) - { - } - - public override void VisitUsingStatement(UsingStatementSyntax node) - { - } - - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) - { - } - - public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) - { - } - - public override void VisitLiteralExpression(LiteralExpressionSyntax node) - { - } - - public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node) - { - } - - public override void VisitOmittedTypeArgument(OmittedTypeArgumentSyntax node) - { - } - - public override void VisitTypeArgumentList(TypeArgumentListSyntax node) - { - } - - public override void VisitTypeParameter(TypeParameterSyntax node) - { - } - - public override void VisitTypeParameterList(TypeParameterListSyntax node) - { - } - - public override void VisitTypeParameterConstraintClause(TypeParameterConstraintClauseSyntax node) - { - } - - public override void DefaultVisit(SyntaxNode node) - { - VisitRelatedSymbols(node); - base.DefaultVisit(node); - } - - private void VisitRelatedSymbols(SyntaxNode syntaxNode) - { - if ((syntaxNode.IsKind(SyntaxKind.IdentifierName) || - syntaxNode.IsKind(SyntaxKind.ElementAccessExpression) || - syntaxNode.IsKind(SyntaxKind.SimpleMemberAccessExpression)) && _visitedNodes.Contains(syntaxNode) == false) - { - _visitedNodes.Add(syntaxNode); - foreach (var relatedNode in _reEntrantCallFinder.GetRelatedNodes(_compilation, _semanticModel, syntaxNode).Where(node => _visitedNodes.Contains(node) == false)) - { - Visit(relatedNode); - } - } - } - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs index 5610884f..6780951e 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; @@ -36,7 +35,7 @@ public IReadOnlyList GetReEntrantCalls( return reEntrantSymbols.Concat(otherSubstitutions).ToList().AsReadOnly(); } - protected virtual IEnumerable GetPotentialOtherSubstituteInvocations(Compilation compilation, IEnumerable operations) + private IEnumerable GetPotentialOtherSubstituteInvocations(Compilation compilation, IEnumerable operations) { foreach (var operation in operations) { @@ -49,47 +48,6 @@ protected virtual IEnumerable GetPotentialOtherSubstituteI } } - protected IEnumerable GetRelatedNodes(Compilation compilation, SemanticModel semanticModel, SyntaxNode syntaxNode) - { - if (compilation.ContainsSyntaxTree(syntaxNode.SyntaxTree) == false) - { - yield break; - } - - var symbol = GetSemanticModel(compilation, semanticModel, syntaxNode).GetSymbolInfo(syntaxNode); - if (symbol.Symbol == null || symbol.Symbol.IsLocal() || symbol.Symbol.Locations.Length == 0) - { - yield break; - } - - foreach (var symbolLocation in symbol.Symbol.Locations.Where(location => location.SourceTree != null)) - { - var root = symbolLocation.SourceTree.GetRoot(); - var relatedNode = root.FindNode(symbolLocation.SourceSpan); - if (relatedNode != null) - { - yield return relatedNode; - } - } - } - - protected SemanticModel GetSemanticModel(Compilation compilation, SemanticModel semanticModel, SyntaxNode syntaxNode) - { - // perf - take original semantic model whenever possible - if (semanticModel.SyntaxTree == syntaxNode.SyntaxTree) - { - return semanticModel; - } - - // but keep in mind that we might traverse outside of the original one https://github.com/nsubstitute/NSubstitute.Analyzers/issues/56 - return compilation.GetSemanticModel(syntaxNode.SyntaxTree); - } - - protected bool IsInnerReEntryLikeMethod(SemanticModel semanticModel, ISymbol symbol) - { - return symbol.IsInnerReEntryLikeMethod(); - } - private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol rootNodeSymbol) { if (rootNodeSymbol == null) @@ -106,8 +64,10 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compi yield break; } - var ancestorChildNodes = rootOperation.Ancestors().SelectMany(ancestor => ancestor.Children); - foreach (var operation in GetPotentialOtherSubstituteInvocations(compilation, ancestorChildNodes)) + // TODO make it nicer + var constructorOperations = GetConstructorOperations(compilation, rootIdentifierSymbol); + var ancestorOperations = rootOperation.Ancestors().SelectMany(ancestor => ancestor.Children).Concat(constructorOperations); + foreach (var operation in GetPotentialOtherSubstituteInvocations(compilation, ancestorOperations)) { if (operation.TargetMethod.IsReturnLikeMethod() == false) { @@ -137,16 +97,32 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compi } } + private static IEnumerable GetConstructorOperations(Compilation compilation, ISymbol fieldReferenceOperation) + { + // TODO naming + foreach (var location in fieldReferenceOperation.ContainingType.GetMembers().OfType() + .Where(methodSymbol => methodSymbol.MethodKind is MethodKind.Constructor or MethodKind.StaticConstructor && methodSymbol.Locations.Length > 0) + .SelectMany(x => x.Locations) + .Where(location => location.IsInSource)) + { + var root = location.SourceTree.GetRoot(); + var relatedNode = root.FindNode(location.SourceSpan); + + // TODO reuse semantic model + var semanticModel = compilation.GetSemanticModel(location.SourceTree); + var operation = semanticModel.GetOperation(relatedNode) ?? semanticModel.GetOperation(relatedNode.Parent); + + if (operation is not null) + { + yield return operation; + } + } + } + private IOperation GetLocalReferenceOperation(IOperation node) { - // TODO can it be done better? var child = node.Children.FirstOrDefault(); - return child switch - { - ILocalReferenceOperation _ => child, - IFieldReferenceOperation _ => child, - _ => null - }; + return child is ILocalReferenceOperation or IFieldReferenceOperation ? child : null; } private IEnumerable GetReEntrantSymbols(Compilation compilation, IInvocationOperation invocationOperation, IOperation rootNode) @@ -196,7 +172,10 @@ private void VisitRelatedSymbols(IInvocationOperation invocationOperation) { var root = location.SourceTree.GetRoot(); var relatedNode = root.FindNode(location.SourceSpan); - Visit(GetSemanticModel(relatedNode).GetOperation(relatedNode)); + var semanticModel = GetSemanticModel(relatedNode); + var operation = semanticModel.GetOperation(relatedNode) ?? + semanticModel.GetOperation(relatedNode.Parent); + Visit(operation); } } diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 431cde57..183ce52c 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -1,9 +1,3 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; @@ -16,140 +10,4 @@ private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) : base(substitutionNodeFinder) { } - - private class ReEntrantCallVisitor : VisualBasicSyntaxWalker - { - private readonly ReEntrantCallFinder _reEntrantCallFinder; - private readonly Compilation _compilation; - private readonly SemanticModel _semanticModel; - private readonly HashSet _visitedNodes = new (); - private readonly List _invocationSymbols = new (); - - public ImmutableList InvocationSymbols => _invocationSymbols.ToImmutableList(); - - public ReEntrantCallVisitor(ReEntrantCallFinder reEntrantCallFinder, Compilation compilation, SemanticModel semanticModel) - { - _reEntrantCallFinder = reEntrantCallFinder; - _compilation = compilation; - _semanticModel = semanticModel; - } - - public override void VisitInvocationExpression(InvocationExpressionSyntax node) - { - if (_visitedNodes.Contains(node) == false && _compilation.ContainsSyntaxTree(node.SyntaxTree)) - { - var semanticModel = _reEntrantCallFinder.GetSemanticModel(_compilation, _semanticModel, node); - var symbolInfo = semanticModel.GetSymbolInfo(node); - if (_reEntrantCallFinder.IsInnerReEntryLikeMethod(semanticModel, symbolInfo.Symbol)) - { - _invocationSymbols.Add(symbolInfo.Symbol); - } - } - - base.VisitInvocationExpression(node); - } - - public override void VisitClassBlock(ClassBlockSyntax node) - { - } - - public override void VisitStructureBlock(StructureBlockSyntax node) - { - } - - public override void VisitTrivia(SyntaxTrivia trivia) - { - } - - public override void VisitLeadingTrivia(SyntaxToken token) - { - } - - public override void VisitTrailingTrivia(SyntaxToken token) - { - } - - public override void VisitAttribute(AttributeSyntax node) - { - } - - public override void VisitAttributesStatement(AttributesStatementSyntax node) - { - } - - public override void VisitAttributeList(AttributeListSyntax node) - { - } - - public override void VisitAttributeTarget(AttributeTargetSyntax node) - { - } - - public override void VisitImportsStatement(ImportsStatementSyntax node) - { - } - - public override void VisitEnumBlock(EnumBlockSyntax node) - { - } - - public override void VisitEnumStatement(EnumStatementSyntax node) - { - } - - public override void VisitLiteralExpression(LiteralExpressionSyntax node) - { - } - - public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node) - { - } - - public override void VisitTypeArgumentList(TypeArgumentListSyntax node) - { - } - - public override void VisitTypeParameter(TypeParameterSyntax node) - { - } - - public override void VisitTypeParameterList(TypeParameterListSyntax node) - { - } - - public override void VisitTypeParameterMultipleConstraintClause(TypeParameterMultipleConstraintClauseSyntax node) - { - } - - public override void VisitTypeParameterSingleConstraintClause(TypeParameterSingleConstraintClauseSyntax node) - { - } - - public override void DefaultVisit(SyntaxNode node) - { - VisitRelatedSymbols(node); - base.DefaultVisit(node); - } - - private void VisitRelatedSymbols(SyntaxNode syntaxNode) - { - if ((syntaxNode.IsKind(SyntaxKind.IdentifierName) || - syntaxNode.IsKind(SyntaxKind.SimpleMemberAccessExpression)) && _visitedNodes.Contains(syntaxNode) == false) - { - _visitedNodes.Add(syntaxNode); - foreach (var relatedNode in _reEntrantCallFinder.GetRelatedNodes(_compilation, _semanticModel, syntaxNode).Where(node => _visitedNodes.Contains(node) == false)) - { - var currentNode = relatedNode; - - // hack getting related symbols for method identifier doesnt return method block but method statement syntax - if (syntaxNode.IsKind(SyntaxKind.IdentifierName) && currentNode is MethodStatementSyntax && _visitedNodes.Contains(relatedNode.Parent) == false) - { - currentNode = relatedNode.Parent; - } - - Visit(currentNode); - } - } - } - } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticResult.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticResult.cs deleted file mode 100644 index 6dbcdd34..00000000 --- a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticResult.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; - -/// -/// Struct that stores information about a Diagnostic appearing in a source -/// -public struct DiagnosticResult -{ - private DiagnosticResultLocation[] _locations; - - public DiagnosticResultLocation[] Locations - { - get - { - if (_locations == null) - { - _locations = new DiagnosticResultLocation[] { }; - } - - return _locations; - } - - set - { - _locations = value; - } - } - - public DiagnosticSeverity Severity { get; set; } - - public string Id { get; set; } - - public string Message { get; set; } - - public string Path - { - get - { - return Locations.Length > 0 ? Locations[0].Path : string.Empty; - } - } - - public int Line - { - get - { - return Locations.Length > 0 ? Locations[0].Line : -1; - } - } - - public int Column - { - get - { - return Locations.Length > 0 ? Locations[0].Column : -1; - } - } -} \ No newline at end of file From 070ec4d1099f82e5bd8176cff39911030be7af5b Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 01:56:35 +0200 Subject: [PATCH 17/35] GH-153 - clean up --- ...nstructorArgumentsForInterfaceCodeFixProvider.cs | 4 ++-- .../DiagnosticAnalyzers/CallInfoAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/CallInfoCallFinder.cs | 12 ------------ .../ConflictingArgumentAssignmentsAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/ReEntrantCallFinder.cs | 13 ------------- .../DiagnosticAnalyzers/AbstractCallInfoFinder.cs | 4 +++- .../AbstractReEntrantCallFinder.cs | 6 ++++-- .../DiagnosticAnalyzers/CallInfoAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/CallInfoCallFinder.cs | 12 ------------ .../ConflictingArgumentAssignmentsAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/ReEntrantCallFinder.cs | 13 ------------- 11 files changed, 13 insertions(+), 59 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs delete mode 100644 src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs index 51c04683..3f117a64 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -19,8 +19,8 @@ protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithE protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithNullConstructorArgument(InvocationExpressionSyntax invocationExpressionSyntax) { var nullSyntax = Argument(LiteralExpression(SyntaxKind.NullLiteralExpression)); - var seconArgument = invocationExpressionSyntax.ArgumentList.Arguments.Skip(1).First(); - var argumentListSyntax = invocationExpressionSyntax.ArgumentList.ReplaceNode(seconArgument, nullSyntax); + var secondArgument = invocationExpressionSyntax.ArgumentList.Arguments.Skip(1).First(); + var argumentListSyntax = invocationExpressionSyntax.ArgumentList.ReplaceNode(secondArgument, nullSyntax); return invocationExpressionSyntax.WithArgumentList(argumentListSyntax); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs index 68838f00..b72a6373 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer { public CallInfoAnalyzer() - : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance, SubstitutionNodeFinder.Instance) + : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoFinder.Instance, SubstitutionNodeFinder.Instance) { } diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs deleted file mode 100644 index 97e44d5f..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/CallInfoCallFinder.cs +++ /dev/null @@ -1,12 +0,0 @@ -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; - -internal class CallInfoCallFinder : AbstractCallInfoFinder -{ - public static CallInfoCallFinder Instance { get; } = new (); - - private CallInfoCallFinder() - { - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index 232a61c9..5f03b3db 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer { public ConflictingArgumentAssignmentsAnalyzer() - : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance) + : base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoFinder.Instance) { } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs deleted file mode 100644 index e77b6d89..00000000 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; - -internal class ReEntrantCallFinder : AbstractReEntrantCallFinder -{ - public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); - - private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) - : base(substitutionNodeFinder) - { - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs index 8489cb37..d2573220 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs @@ -6,8 +6,10 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractCallInfoFinder : ICallInfoFinder +internal class CallInfoFinder : ICallInfoFinder { + public static CallInfoFinder Instance { get; } = new (); + public CallInfoContext GetCallInfoContext(IArgumentOperation argumentOperation) { var callInfoContext = CallInfoContext.Empty; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs index 6780951e..a3455f82 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs @@ -8,11 +8,13 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractReEntrantCallFinder : IReEntrantCallFinder +internal class ReEntrantCallFinder : IReEntrantCallFinder { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - protected AbstractReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) + public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); + + protected ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) { _substitutionNodeFinder = substitutionNodeFinder; } diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs index d9ca8eb5..19cc1452 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoAnalyzer.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer { public CallInfoAnalyzer() - : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance, SubstitutionNodeFinder.Instance) + : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoFinder.Instance, SubstitutionNodeFinder.Instance) { } diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs deleted file mode 100644 index 8ae44519..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/CallInfoCallFinder.cs +++ /dev/null @@ -1,12 +0,0 @@ -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal class CallInfoCallFinder : AbstractCallInfoFinder -{ - public static CallInfoCallFinder Instance { get; } = new (); - - private CallInfoCallFinder() - { - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index 1b4bb28c..bfdd4520 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer { public ConflictingArgumentAssignmentsAnalyzer() - : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance) + : base(NSubstitute.Analyzers.VisualBasic.DiagnosticDescriptorsProvider.Instance, CallInfoFinder.Instance) { } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs deleted file mode 100644 index 183ce52c..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; - -namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; - -internal class ReEntrantCallFinder : AbstractReEntrantCallFinder -{ - public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); - - private ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) - : base(substitutionNodeFinder) - { - } -} \ No newline at end of file From 4383b1ce4b58465952fd3673ab8cf2b5833a8956 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 03:19:04 +0200 Subject: [PATCH 18/35] GH-153 - using operations api in WithAnyArgsArgumentMatcherAnalyzer --- Directory.Build.props | 4 +- .../CSharpDiagnosticAnalyzersBenchmarks.cs | 2 +- .../WithAnyArgsArgumentMatcherAnalyzer.cs | 14 +-- ...tractWithAnyArgsArgumentMatcherAnalyzer.cs | 101 +++++++----------- .../WithAnyArgsArgumentMatcherAnalyzer.cs | 15 +-- .../VisualBasicProjectOptions.cs | 2 +- .../VisualBasicWorkspaceFactory.cs | 2 +- 7 files changed, 47 insertions(+), 93 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cb06957c..f81d050e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,10 +5,10 @@ latest - + - + true diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs index 1117fd20..252fe780 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs @@ -60,6 +60,6 @@ public CSharpDiagnosticAnalyzersBenchmarks() ReceivedInReceivedInOrderAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new ReceivedInReceivedInOrderAnalyzer()); AsyncReceivedInOrderCallbackAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new AsyncReceivedInOrderCallbackAnalyzer()); SyncOverAsyncThrowsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new SyncOverAsyncThrowsAnalyzer()); - WithAnyArgsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new WithAnyArgsArgumentMatcherAnalyzer()); + WithAnyArgsAnalyzerBenchmark = AnalyzerBenchmark.CreateBenchmark(Solution, new WithAnyArgsArgumentMatcherAnalyzer()); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs index fb347b87..0bdc4f2f 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs @@ -1,26 +1,14 @@ -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 WithAnyArgsArgumentMatcherAnalyzer : AbstractWithAnyArgsArgumentMatcherAnalyzer +internal sealed class WithAnyArgsArgumentMatcherAnalyzer : AbstractWithAnyArgsArgumentMatcherAnalyzer { - internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.InvocationExpression, - (int)SyntaxKind.ElementAccessExpression, - (int)SyntaxKind.SimpleAssignmentExpression); - public WithAnyArgsArgumentMatcherAnalyzer() : base(CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance) { } - - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = MaybeAllowedAncestors; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs index 9696ac6b..c7e3da63 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs @@ -9,16 +9,13 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal abstract class AbstractWithAnyArgsArgumentMatcherAnalyzer : AbstractDiagnosticAnalyzer - where TInvocationExpressionSyntax : SyntaxNode - where TSyntaxKind : struct, Enum +internal abstract class AbstractWithAnyArgsArgumentMatcherAnalyzer : AbstractDiagnosticAnalyzer { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - private readonly Action _analyzeInvocationAction; + private readonly Action _analyzeInvocationAction; - protected abstract ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } - - protected abstract TSyntaxKind InvocationExpressionKind { get; } + private static readonly ImmutableHashSet MaybeAllowedArgMatcherAncestors = + ImmutableHashSet.Create(OperationKind.Invocation, OperationKind.ObjectCreation, OperationKind.SimpleAssignment); protected AbstractWithAnyArgsArgumentMatcherAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -34,40 +31,38 @@ protected AbstractWithAnyArgsArgumentMatcherAnalyzer( protected override void InitializeAnalyzer(AnalysisContext context) { - context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); + context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + private void AnalyzeInvocation(OperationAnalysisContext context) { - var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; - var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); - - if (methodSymbolInfo.Symbol is not IMethodSymbol methodSymbol) + if (context.Operation is not IInvocationOperation invocationOperation) { return; } + var methodSymbol = invocationOperation.TargetMethod; if (methodSymbol.IsWithAnyArgsIncompatibleArgMatcherLikeMethod()) { - AnalyzeArgLikeMethodForReceivedWithAnyArgs(syntaxNodeContext, invocationExpression, methodSymbol); + AnalyzeArgLikeMethodForReceivedWithAnyArgs(context, invocationOperation); return; } if (methodSymbol.IsReturnForAnyArgsLikeMethod() || methodSymbol.IsThrowForAnyArgsLikeMethod()) { - AnalyzeReturnsLikeMethod(syntaxNodeContext, invocationExpression); + AnalyzeReturnsLikeMethod(context, invocationOperation); return; } if (methodSymbol.IsWhenForAnyArgsLikeMethod()) { - AnalyzeWhenLikeMethod(syntaxNodeContext, invocationExpression); + AnalyzeWhenLikeMethod(context, invocationOperation); } } private void AnalyzeWhenLikeMethod( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax whenMethod) + OperationAnalysisContext context, + IInvocationOperation invocationOperation) { ImmutableArray Arguments(IPropertyReferenceOperation propertyReferenceOperation) { @@ -82,15 +77,8 @@ ImmutableArray Arguments(IPropertyReferenceOperation propertyReferen return builder.ToImmutable(); } - if (syntaxNodeContext.SemanticModel.GetOperation(whenMethod) is not IInvocationOperation invocationOperation) + foreach (var substitutedOperation in _substitutionNodeFinder.FindForWhenExpression(context.Compilation, invocationOperation)) { - return; - } - - foreach (var syntaxNode in _substitutionNodeFinder.FindForWhenExpression(syntaxNodeContext, invocationOperation)) - { - var substitutedOperation = syntaxNodeContext.SemanticModel.GetOperation(syntaxNode); - IReadOnlyList arguments = substitutedOperation switch { IInvocationOperation substituteInvocationOperation => substituteInvocationOperation.Arguments, @@ -100,29 +88,23 @@ ImmutableArray Arguments(IPropertyReferenceOperation propertyReferen foreach (var operation in arguments) { - AnalyzeArgument(syntaxNodeContext, operation); + AnalyzeArgument(context, operation); } } } private void AnalyzeReturnsLikeMethod( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax returnsInvocationExpression) + OperationAnalysisContext context, + IInvocationOperation invocationOperation) { - if (syntaxNodeContext.SemanticModel.GetOperation(returnsInvocationExpression) is not IInvocationOperation - invocationOperation) - { - return; - } - var substitutedOperation = - _substitutionNodeFinder.FindOperationForStandardExpression(invocationOperation); + _substitutionNodeFinder.FindForStandardExpression(invocationOperation); var arguments = GetArguments(substitutedOperation); foreach (var argumentOperation in arguments) { - AnalyzeArgument(syntaxNodeContext, argumentOperation); + AnalyzeArgument(context, argumentOperation); } } @@ -138,24 +120,24 @@ private static IReadOnlyList GetArguments(IOperation substitutedOper return arguments; } - private void AnalyzeArgument(SyntaxNodeAnalysisContext syntaxNodeContext, IOperation operation) + private void AnalyzeArgument(OperationAnalysisContext context, IOperation operation) { if (operation is IConversionOperation conversionOperation) { - AnalyzeArgument(syntaxNodeContext, conversionOperation.Operand); + AnalyzeArgument(context, conversionOperation.Operand); return; } if (operation is IArgumentOperation argumentOperation) { - AnalyzeArgument(syntaxNodeContext, argumentOperation.Value); + AnalyzeArgument(context, argumentOperation.Value); return; } if (operation is IInvocationOperation argInvocationOperation && argInvocationOperation.TargetMethod.IsWithAnyArgsIncompatibleArgMatcherLikeMethod()) { - syntaxNodeContext.TryReportDiagnostic( + context.TryReportDiagnostic( Diagnostic.Create( DiagnosticDescriptorsProvider.WithAnyArgsArgumentMatcherUsage, argInvocationOperation.Syntax.GetLocation()), @@ -164,32 +146,29 @@ private void AnalyzeArgument(SyntaxNodeAnalysisContext syntaxNodeContext, IOpera } private void AnalyzeArgLikeMethodForReceivedWithAnyArgs( - SyntaxNodeAnalysisContext syntaxNodeContext, - TInvocationExpressionSyntax argInvocationExpression, - IMethodSymbol invocationExpressionSymbol) + OperationAnalysisContext context, + IInvocationOperation argInvocationOperation) { - var enclosingExpression = FindMaybeAllowedEnclosingExpression(argInvocationExpression); + var enclosingOperation = FindMaybeAllowedEnclosingOperation(argInvocationOperation); - if (enclosingExpression == null) + if (enclosingOperation == null) { return; } - var operation = syntaxNodeContext.SemanticModel.GetOperation(enclosingExpression); - - if (operation is IInvocationOperation enclosingInvocationOperation && + if (enclosingOperation is IInvocationOperation enclosingInvocationOperation && enclosingInvocationOperation.Instance is IInvocationOperation enclosingInvocationOperationInstance && enclosingInvocationOperationInstance.TargetMethod.IsReceivedWithAnyArgsLikeMethod()) { - syntaxNodeContext.TryReportDiagnostic( + context.TryReportDiagnostic( Diagnostic.Create( DiagnosticDescriptorsProvider.WithAnyArgsArgumentMatcherUsage, - argInvocationExpression.GetLocation()), - invocationExpressionSymbol); + argInvocationOperation.Syntax.GetLocation()), + argInvocationOperation.TargetMethod); return; } - var memberReferenceOperation = GetMemberReferenceOperation(operation); + var memberReferenceOperation = GetMemberReferenceOperation(enclosingOperation); if (memberReferenceOperation is not { Instance: IInvocationOperation invocationOperation } || !invocationOperation.TargetMethod.IsReceivedWithAnyArgsLikeMethod()) @@ -197,11 +176,11 @@ enclosingInvocationOperation.Instance is IInvocationOperation enclosingInvocatio return; } - syntaxNodeContext.TryReportDiagnostic( + context.TryReportDiagnostic( Diagnostic.Create( DiagnosticDescriptorsProvider.WithAnyArgsArgumentMatcherUsage, - argInvocationExpression.GetLocation()), - invocationExpressionSymbol); + argInvocationOperation.Syntax.GetLocation()), + argInvocationOperation.TargetMethod); } private static IMemberReferenceOperation GetMemberReferenceOperation(IOperation operation) @@ -220,12 +199,12 @@ private static IMemberReferenceOperation GetMemberReferenceOperation(IOperation }; } - private SyntaxNode FindMaybeAllowedEnclosingExpression(TInvocationExpressionSyntax invocationExpression) => - FindEnclosingExpression(invocationExpression, MaybeAllowedArgMatcherAncestors); + private IOperation FindMaybeAllowedEnclosingOperation(IInvocationOperation invocationOperation) => + FindEnclosingOperation(invocationOperation, MaybeAllowedArgMatcherAncestors); - private static SyntaxNode FindEnclosingExpression(TInvocationExpressionSyntax invocationExpression, ImmutableHashSet ancestors) + private static IOperation FindEnclosingOperation(IInvocationOperation invocationOperation, ImmutableHashSet ancestors) { - return invocationExpression.Ancestors() - .FirstOrDefault(ancestor => ancestors.Contains(ancestor.RawKind)); + return invocationOperation.Ancestors() + .FirstOrDefault(ancestor => ancestors.Contains(ancestor.Kind)); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs index 3b8faccb..24bee253 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/WithAnyArgsArgumentMatcherAnalyzer.cs @@ -1,27 +1,14 @@ -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 sealed class WithAnyArgsArgumentMatcherAnalyzer : AbstractWithAnyArgsArgumentMatcherAnalyzer +internal sealed class WithAnyArgsArgumentMatcherAnalyzer : AbstractWithAnyArgsArgumentMatcherAnalyzer { - internal static ImmutableHashSet MaybeAllowedAncestors { get; } = ImmutableHashSet.Create( - (int)SyntaxKind.InvocationExpression, - (int)SyntaxKind.ObjectCreationExpression, - (int)SyntaxKind.EqualsExpression, - (int)SyntaxKind.SimpleAssignmentStatement); - public WithAnyArgsArgumentMatcherAnalyzer() : base(VisualBasic.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance) { } - - protected override ImmutableHashSet MaybeAllowedArgMatcherAncestors { get; } = MaybeAllowedAncestors; - - protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs index e64a81eb..b8ac19f1 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicProjectOptions.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic; public class VisualBasicProjectOptions : ProjectOptions { - public static VisualBasicProjectOptions Default { get; } = new ( + public static VisualBasicProjectOptions Default { get; } = new( RuntimeMetadataReference.Default.Add(MetadataReference.CreateFromFile(typeof(StandardModuleAttribute).Assembly.Location)), new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs index 85451de5..1e743ad1 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/VisualBasicWorkspaceFactory.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic; public class VisualBasicWorkspaceFactory : WorkspaceFactory { - public static VisualBasicWorkspaceFactory Default { get; } = new (VisualBasicProjectOptions.Default); + public static VisualBasicWorkspaceFactory Default { get; } = new(VisualBasicProjectOptions.Default); protected override string DocumentExtension { get; } = "vb"; From 12dbe988e674c0d156d83c5a6f4ab9cee8da3ea0 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 03:22:49 +0200 Subject: [PATCH 19/35] GH-153 - clean up --- .../Shared/AnalyzerBenchmark.cs | 24 +++++++++---------- .../SubstituteConstructorMatcher.cs | 2 +- .../DiagnosticDescriptorsProvider.cs | 2 +- .../AbstractSubstituteConstructorMatcher.cs | 2 +- .../DiagnosticAnalyzers/CallInfoContext.cs | 2 +- ...actCallInfoFinder.cs => CallInfoFinder.cs} | 8 +++---- ...ntCallFinder.cs => ReEntrantCallFinder.cs} | 8 +++---- ...is.cs => SubstituteConstructorAnalysis.cs} | 2 +- ...Analysis.cs => SubstituteProxyAnalysis.cs} | 2 +- ...odeFinder.cs => SubstitutionNodeFinder.cs} | 6 ++--- .../DiagnosticDescriptors.cs | 2 +- .../Settings/AnalyzersSettings.cs | 4 ++-- .../SharedResourceManager.cs | 2 +- .../TinyJson/JsonBuilder.cs | 2 +- .../TinyJson/JsonMapper.cs | 4 ++-- .../TinyJson/JsonParser.cs | 2 +- .../SubstituteConstructorMatcher.cs | 2 +- .../DiagnosticDescriptorsProvider.cs | 2 +- .../CSharpProjectOptions.cs | 2 +- .../CSharpWorkspaceFactory.cs | 2 +- .../Text/LinePositionInfo.cs | 2 +- .../Text/LinePositionSpanInfo.cs | 2 +- 22 files changed, 43 insertions(+), 43 deletions(-) rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractCallInfoFinder.cs => CallInfoFinder.cs} (98%) rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractReEntrantCallFinder.cs => ReEntrantCallFinder.cs} (97%) rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractSubstituteConstructorAnalysis.cs => SubstituteConstructorAnalysis.cs} (99%) rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractSubstituteProxyAnalysis.cs => SubstituteProxyAnalysis.cs} (99%) rename src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/{AbstractSubstitutionNodeFinder.cs => SubstitutionNodeFinder.cs} (98%) diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs index c93e11e8..8f7ffda2 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs @@ -188,29 +188,29 @@ public void Run() [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] private class BenchmarkAnalyzer : DiagnosticAnalyzer { - internal List> SyntaxNodeActions { get; } = new (); + internal List> SyntaxNodeActions { get; } = new(); - internal List> CompilationStartActions { get; } = new (); + internal List> CompilationStartActions { get; } = new(); - internal List> CompilationEndActions { get; } = new (); + internal List> CompilationEndActions { get; } = new(); - internal List> CompilationActions { get; } = new (); + internal List> CompilationActions { get; } = new(); - internal List> SemanticModelActions { get; } = new (); + internal List> SemanticModelActions { get; } = new(); - internal List> SymbolActions { get; } = new (); + internal List> SymbolActions { get; } = new(); - internal List CodeBlockStartActions { get; } = new (); + internal List CodeBlockStartActions { get; } = new(); - internal List> CodeBlockActions { get; } = new (); + internal List> CodeBlockActions { get; } = new(); - internal List> SyntaxTreeActions { get; } = new (); + internal List> SyntaxTreeActions { get; } = new(); - internal List> OperationActions { get; } = new (); + internal List> OperationActions { get; } = new(); - internal List> OperationBlockActions { get; } = new (); + internal List> OperationBlockActions { get; } = new(); - internal List> OperationBlockStartActions { get; } = new (); + internal List> OperationBlockStartActions { get; } = new(); private readonly DiagnosticAnalyzer _inner; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index 1fab074f..9fb57a31 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { - public static SubstituteConstructorMatcher Instance { get; } = new (); + public static SubstituteConstructorMatcher Instance { get; } = new(); private SubstituteConstructorMatcher() { diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs index 1f4f07fd..703c5642 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticDescriptorsProvider.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.CSharp; internal class DiagnosticDescriptorsProvider : AbstractDiagnosticDescriptorsProvider { - public static DiagnosticDescriptorsProvider Instance { get; } = new (); + public static DiagnosticDescriptorsProvider Instance { get; } = new(); private DiagnosticDescriptorsProvider() { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs index e7d194b1..c187d021 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorMatcher.cs @@ -21,7 +21,7 @@ internal abstract class AbstractSubstituteConstructorMatcher : ISubstituteConstr private static IReadOnlyDictionary> WellKnownSupportedConversions { get; } = new Dictionary> { - [SpecialType.System_Char] = new () + [SpecialType.System_Char] = new() { SpecialType.System_Int16, SpecialType.System_Int32, diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs index f910d133..f94a9f6d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoContext.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class CallInfoContext { - public static CallInfoContext Empty { get; } = new ( + public static CallInfoContext Empty { get; } = new( Array.Empty(), Array.Empty(), Array.Empty()); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs similarity index 98% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs index d2573220..655fd824 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class CallInfoFinder : ICallInfoFinder { - public static CallInfoFinder Instance { get; } = new (); + public static CallInfoFinder Instance { get; } = new(); public CallInfoContext GetCallInfoContext(IArgumentOperation argumentOperation) { @@ -121,11 +121,11 @@ private static IParameterSymbol GetCallInfoParameterSymbol(IOperation operation) private class CallInfoVisitor : OperationWalker { - public List ArgAtInvocations { get; } = new (); + public List ArgAtInvocations { get; } = new(); - public List ArgInvocations { get; } = new (); + public List ArgInvocations { get; } = new(); - public List DirectIndexerAccesses { get; } = new (); + public List DirectIndexerAccesses { get; } = new(); public override void VisitInvocation(IInvocationOperation operation) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs similarity index 97% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs index a3455f82..5d078b0b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -12,7 +12,7 @@ internal class ReEntrantCallFinder : IReEntrantCallFinder { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - public static ReEntrantCallFinder Instance { get; } = new (SubstitutionNodeFinder.Instance); + public static ReEntrantCallFinder Instance { get; } = new(SubstitutionNodeFinder.Instance); protected ReEntrantCallFinder(ISubstitutionNodeFinder substitutionNodeFinder) { @@ -138,9 +138,9 @@ private IEnumerable GetReEntrantSymbols(Compilation compilation, IIn private class ReEntrantCallVisitor : OperationWalker { private readonly Compilation _compilation; - private readonly HashSet _visitedOperations = new (); - private readonly List _invocationOperation = new (); - private readonly Dictionary _semanticModelCache = new (1); + private readonly HashSet _visitedOperations = new(); + private readonly List _invocationOperation = new(); + private readonly Dictionary _semanticModelCache = new(1); public ImmutableList InvocationOperations => _invocationOperation.ToImmutableList(); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs similarity index 99% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs index d774d1db..c637f482 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class SubstituteConstructorAnalysis : ISubstituteConstructorAnalysis { - public static SubstituteConstructorAnalysis Instance { get; } = new (); + public static SubstituteConstructorAnalysis Instance { get; } = new(); public ConstructorContext CollectConstructorContext(SubstituteContext substituteContext, ITypeSymbol proxyTypeSymbol) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs similarity index 99% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs index 7291eb07..ad8a8b61 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs @@ -7,7 +7,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class SubstituteProxyAnalysis : ISubstituteProxyAnalysis { - public static SubstituteProxyAnalysis Instance { get; } = new (); + public static SubstituteProxyAnalysis Instance { get; } = new(); public ITypeSymbol GetActualProxyTypeSymbol(IInvocationOperation invocationOperation) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs similarity index 98% rename from src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs rename to src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 0c09b9ac..406903b3 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -9,7 +9,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal class SubstitutionNodeFinder : ISubstitutionNodeFinder { - public static SubstitutionNodeFinder Instance { get; } = new (); + public static SubstitutionNodeFinder Instance { get; } = new(); public IEnumerable Find( Compilation compilation, @@ -133,9 +133,9 @@ private class WhenVisitor : OperationWalker private readonly Compilation _compilation; private readonly IInvocationOperation _whenInvocationOperation; private readonly bool _includeAll; - private readonly HashSet _operations = new (); + private readonly HashSet _operations = new(); - private readonly Dictionary _semanticModelCache = new (1); + private readonly Dictionary _semanticModelCache = new(1); public WhenVisitor( Compilation compilation, diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs index 1968fe32..da0b0d48 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs @@ -7,7 +7,7 @@ namespace NSubstitute.Analyzers.Shared; internal class DiagnosticDescriptors { - private static readonly ResourceManager SpecificResourceManager = new ( + private static readonly ResourceManager SpecificResourceManager = new( $"{typeof(T).GetTypeInfo().Assembly.GetName().Name}.Resources", typeof(T).GetTypeInfo().Assembly); diff --git a/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs b/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs index 590e9b65..308c3f59 100644 --- a/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs +++ b/src/NSubstitute.Analyzers.Shared/Settings/AnalyzersSettings.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Shared.Settings; internal class AnalyzersSettings { - public static AnalyzersSettings Default => new (); + public static AnalyzersSettings Default => new(); public List Suppressions { get; set; } @@ -24,7 +24,7 @@ public static AnalyzersSettings CreateWithSuppressions(string target, string rul { return new AnalyzersSettings(new List { - new () + new() { Target = target, Rules = new List diff --git a/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs b/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs index af4856e7..21f3a95a 100644 --- a/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs +++ b/src/NSubstitute.Analyzers.Shared/SharedResourceManager.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Shared; internal class SharedResourceManager { - internal static ResourceManager Instance { get; } = new ( + internal static ResourceManager Instance { get; } = new( $"{typeof(SharedResourceManager).GetTypeInfo().Assembly.GetName().Name}.Resources", typeof(SharedResourceManager).GetTypeInfo().Assembly); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs index 80f0e537..54bbf82a 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonBuilder.cs @@ -8,7 +8,7 @@ namespace NSubstitute.Analyzers.Shared.TinyJson; [ExcludeFromCodeCoverage] internal class JsonBuilder { - private StringBuilder _builder = new (); + private StringBuilder _builder = new(); private bool _pretty = false; private int _level; diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs index 6a9a3337..ce088b0f 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonMapper.cs @@ -14,8 +14,8 @@ internal static class JsonMapper { private static Encoder genericEncoder; private static Decoder genericDecoder; - private static Dictionary encoders = new (); - private static Dictionary decoders = new (); + private static Dictionary encoders = new(); + private static Dictionary decoders = new(); internal static Encoder GenericEncoder { get => genericEncoder; set => genericEncoder = value; } diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs index 8769a1da..f0155f46 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs @@ -27,7 +27,7 @@ private enum Token private StringReader _json; // temporary allocated - private StringBuilder _sb = new (); + private StringBuilder _sb = new(); public static object ParseValue(string jsonString) { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index 7e1c046f..c84c7526 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { - public static SubstituteConstructorMatcher Instance { get; } = new (); + public static SubstituteConstructorMatcher Instance { get; } = new(); private SubstituteConstructorMatcher() { diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs index b31611f9..be78178c 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticDescriptorsProvider.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.VisualBasic; internal class DiagnosticDescriptorsProvider : AbstractDiagnosticDescriptorsProvider { - public static DiagnosticDescriptorsProvider Instance { get; } = new (); + public static DiagnosticDescriptorsProvider Instance { get; } = new(); private DiagnosticDescriptorsProvider() { diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs index c328ceb8..c06ddf9e 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpProjectOptions.cs @@ -7,7 +7,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp; public class CSharpProjectOptions : ProjectOptions { - public static CSharpProjectOptions Default { get; } = new ( + public static CSharpProjectOptions Default { get; } = new( RuntimeMetadataReference.Default, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs index aa4aae01..276d4432 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CSharpWorkspaceFactory.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp; public class CSharpWorkspaceFactory : WorkspaceFactory { - public static CSharpWorkspaceFactory Default { get; } = new (CSharpProjectOptions.Default); + public static CSharpWorkspaceFactory Default { get; } = new(CSharpProjectOptions.Default); protected override string DocumentExtension { get; } = "cs"; diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs index 41a94c03..00c49614 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionInfo.cs @@ -17,5 +17,5 @@ public LinePositionInfo(int index, int lineIndex, int columnIndex) public int ColumnIndex { get; } - public LinePosition LinePosition => new (LineIndex, ColumnIndex); + public LinePosition LinePosition => new(LineIndex, ColumnIndex); } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs index 87c276a7..48b3e43f 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/Text/LinePositionSpanInfo.cs @@ -16,5 +16,5 @@ public LinePositionSpanInfo(in LinePositionInfo start, in LinePositionInfo end) public TextSpan Span => TextSpan.FromBounds(Start.Index, End.Index); - public LinePositionSpan LineSpan => new (Start.LinePosition, End.LinePosition); + public LinePositionSpan LineSpan => new(Start.LinePosition, End.LinePosition); } \ No newline at end of file From e4f2a778929518a53a2c49cf77598dc4e663144e Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 17:21:50 +0200 Subject: [PATCH 20/35] GH-153 - adding missing test cases for out of order parameters --- .../ReturnsAsOrdinaryMethodTests.cs | 78 ++++++++++++++++ .../ThrowsAsOrdinaryMethodTests.cs | 83 +++++++++++++++++ ...SubstitutableMemberArgumentMatcherTests.cs | 90 +++++++++++++++++-- .../WhenAsOrdinaryMethodTests.cs | 1 + .../ReceivedAsOrdinaryMethodTests.cs | 21 ++++- 5 files changed, 264 insertions(+), 9 deletions(-) diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 7b16a0d9..22dc04b5 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -551,7 +551,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar, 1); + {method}(value: substitute.Bar, returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar); {method}([|substitute.FooBar|], 1); + {method}(value: [|substitute.FooBar|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute.FooBar|]); }} }} }}"; @@ -615,7 +619,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar(1, 2), 1); + {method}(value: substitute.Bar(1, 2), returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar(1, 2)); {method}([|substitute.Bar(1)|], 1); + {method}(value: [|substitute.Bar(1)|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute.Bar(1)|]); }} }} }}"; @@ -650,7 +658,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar(1, 2), 1); + {method}(value: substitute.Bar(1, 2), returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar(1, 2)); {method}([|substitute.Bar(1)|], 1); + {method}(value: [|substitute.Bar(1)|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute.Bar(1)|]); }} }} }}"; @@ -678,7 +690,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1,2], 1); + {method}(value: substitute[1,2], returnThis: 1); + {method}(returnThis: 1, value: substitute[1,2]); {method}([|substitute[1]|], 1); + {method}(value: [|substitute[1]|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute[1]|]); }} }} }}"; @@ -706,7 +722,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>(); {method}(substitute[1, 2], 1); + {method}(value: substitute[1, 2], returnThis: 1); + {method}(returnThis: 1, value: substitute[1, 2]); {method}([|substitute[1]|], 1); + {method}(value: [|substitute[1]|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute[1]|]); }} }} }}"; @@ -748,13 +768,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1], 1); + {method}(value: substitute[1], returnThis: 1); + {method}(returnThis: 1, value: substitute[1]); {method}(substitute.Bar, 1); + {method}(value: substitute.Bar, returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar); {method}(substitute.FooBar(), 1); + {method}(value: substitute.FooBar(), returnThis: 1); + {method}(returnThis: 1, value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For(); {method}([|substituteFooBarBar[1]|], 1); + {method}(value: [|substituteFooBarBar[1]|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], 1); + {method}(value: [|substituteFooBarBar.Bar|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], 1); + {method}(value: [|substituteFooBarBar.FooBar()|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -763,8 +795,14 @@ public void Test() var diagnosticMessages = new[] { + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -807,13 +845,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>(); {method}(substitute[1], 1); + {method}(value: substitute[1], returnThis: 1); + {method}(returnThis: 1, value: substitute[1]); {method}(substitute.Bar, 1); + {method}(value: substitute.Bar, returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar); {method}(substitute.FooBar(), 1); + {method}(value: substitute.FooBar(), returnThis: 1); + {method}(returnThis: 1, value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For>(); {method}([|substituteFooBarBar[1]|], 1); + {method}(value: [|substituteFooBarBar[1]|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], 1); + {method}(value: [|substituteFooBarBar.Bar|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], 1); + {method}(value: [|substituteFooBarBar.FooBar()|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -823,7 +873,13 @@ public void Test() var diagnosticMessages = new[] { "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -870,13 +926,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1], 1); + {method}(value: substitute[1], returnThis: 1); + {method}(returnThis: 1, value: substitute[1]); {method}(substitute.Bar, 1); + {method}(value: substitute.Bar, returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar); {method}(substitute.FooBar(), 1); + {method}(value: substitute.FooBar(), returnThis: 1); + {method}(returnThis: 1, value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For(); {method}([|substituteFooBarBar[1]|], 1); + {method}(value: [|substituteFooBarBar[1]|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], 1); + {method}(value: [|substituteFooBarBar.Bar|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], 1); + {method}(value: [|substituteFooBarBar.FooBar()|], returnThis: 1); + {method}(returnThis: 1, value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -886,7 +954,13 @@ public void Test() var diagnosticMessages = new[] { "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -910,7 +984,11 @@ public void Test() MyExtensions.Bar = Substitute.For(); var substitute = Substitute.For(); {method}(substitute.GetBar(), 1); + {method}(value: substitute.GetBar(), returnThis: 1); + {method}(returnThis: 1, value: substitute.GetBar()); {method}([|substitute.GetFooBar()|], 1); + {method}(value: [|substitute.GetFooBar()|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute.GetFooBar()|]); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index 8d708596..fc3c9874 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -35,6 +35,7 @@ public class FooTests public void Test() {{ var substitute = NSubstitute.Substitute.For(); + {method}([|substitute.Bar()|], new Exception()); {method}(value: [|substitute.Bar()|], ex: new Exception()); {method}(ex: new Exception(), value: [|substitute.Bar()|]); }} @@ -626,7 +627,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar, new Exception()); + {method}(value: substitute.Bar, ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar); {method}([|substitute.FooBar|], new Exception()); + {method}(value: [|substitute.FooBar|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute.FooBar|]); }} }} }}"; @@ -658,7 +663,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>>(); {method}(substitute.Bar, new Exception()); + {method}(value: substitute.Bar, ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar); {method}([|substitute.FooBar|], new Exception()); + {method}(value: [|substitute.FooBar|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute.FooBar|]); }} }} }}"; @@ -696,7 +705,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar(1, 2), new Exception()); + {method}(value: substitute.Bar(1, 2), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar(1, 2)); {method}([|substitute.Bar(1)|], new Exception()); + {method}(value: [|substitute.Bar(1)|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute.Bar(1)|]); }} }} }}"; @@ -734,7 +747,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.Bar(1, 2), new Exception()); + {method}(value: substitute.Bar(1, 2), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar(1, 2)); {method}([|substitute.Bar(1)|], new Exception()); + {method}(value: [|substitute.Bar(1)|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute.Bar(1)|]); }} }} }}"; @@ -765,7 +782,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1,2], new Exception()); + {method}(value: substitute[1,2], ex: new Exception()); + {method}(ex: new Exception(), value: substitute[1,2]); {method}([|substitute[1]|], new Exception()); + {method}(value: [|substitute[1]|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute[1]|]); }} }} }}"; @@ -796,7 +817,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>(); {method}(substitute[1, 2], new Exception()); + {method}(value: substitute[1, 2], ex: new Exception()); + {method}(ex: new Exception(), value: substitute[1, 2]); {method}([|substitute[1]|], new Exception()); + {method}(value: [|substitute[1]|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute[1]|]); }} }} }}"; @@ -841,13 +866,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1], new Exception()); + {method}(value: substitute[1], ex: new Exception()); + {method}(ex: new Exception(), value: substitute[1]); {method}(substitute.Bar, new Exception()); + {method}(value: substitute.Bar, ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar); {method}(substitute.FooBar(), new Exception()); + {method}(value: substitute.FooBar(), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For(); {method}([|substituteFooBarBar[1]|], new Exception()); + {method}(value: [|substituteFooBarBar[1]|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], new Exception()); + {method}(value: [|substituteFooBarBar.Bar|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], new Exception()); + {method}(value: [|substituteFooBarBar.FooBar()|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -857,7 +894,13 @@ public void Test() var diagnosticMessages = new[] { "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -903,13 +946,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>(); {method}(substitute[1], new Exception()); + {method}(value: substitute[1], ex: new Exception()); + {method}(ex: new Exception(), value: substitute[1]); {method}(substitute.Bar, new Exception()); + {method}(value: substitute.Bar, ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar); {method}(substitute.FooBar(), new Exception()); + {method}(value: substitute.FooBar(), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For>(); {method}([|substituteFooBarBar[1]|], new Exception()); + {method}(value: [|substituteFooBarBar[1]|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], new Exception()); + {method}(value: [|substituteFooBarBar.Bar|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], new Exception()); + {method}(value: [|substituteFooBarBar.FooBar()|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -919,7 +974,13 @@ public void Test() var diagnosticMessages = new[] { "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -969,13 +1030,25 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute[1], new Exception()); + {method}(value: substitute[1], ex: new Exception()); + {method}(ex: new Exception(), value: substitute[1]); {method}(substitute.Bar, new Exception()); + {method}(value: substitute.Bar, ex: new Exception()); + {method}(ex: new Exception(), value: substitute.Bar); {method}(substitute.FooBar(), new Exception()); + {method}(value: substitute.FooBar(), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.FooBar()); var substituteFooBarBar = NSubstitute.Substitute.For(); {method}([|substituteFooBarBar[1]|], new Exception()); + {method}(value: [|substituteFooBarBar[1]|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar[1]|]); {method}([|substituteFooBarBar.Bar|], new Exception()); + {method}(value: [|substituteFooBarBar.Bar|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.Bar|]); {method}([|substituteFooBarBar.FooBar()|], new Exception()); + {method}(value: [|substituteFooBarBar.FooBar()|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substituteFooBarBar.FooBar()|]); }} }} }}"; @@ -985,7 +1058,13 @@ public void Test() var diagnosticMessages = new[] { "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted." }; @@ -1012,7 +1091,11 @@ public void Test() MyExtensions.Bar = Substitute.For(); var substitute = Substitute.For(); {method}(substitute.GetBar(), new Exception()); + {method}(value: substitute.GetBar(), ex: new Exception()); + {method}(ex: new Exception(), value: substitute.GetBar()); {method}([|substitute.GetFooBar()|], new Exception()); + {method}(value: [|substitute.GetFooBar()|], ex: new Exception()); + {method}(ex: new Exception(), value: [|substitute.GetFooBar()|]); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs index fd05da0b..656812cd 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs @@ -34,6 +34,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -99,6 +102,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -139,6 +145,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -160,6 +169,9 @@ public void Test() var substitute = Substitute.For>(); substitute({arg}); substitute.When(x => x({arg})); + SubstituteExtensions.When(substitute, x => x({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x({arg})); + SubstituteExtensions.When(substituteCall: x => x({arg}), substitute: substitute); }} }} }}"; @@ -200,6 +212,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -228,6 +243,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -256,6 +274,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -283,6 +304,9 @@ public void Test() var substitute = NSubstitute.Substitute.For>(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -310,6 +334,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); var _ = substitute[{arg}]; substitute.When(x => _ = x[{arg}]); + SubstituteExtensions.When(substitute, x => _ = x[{arg}]); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => _ = x[{arg}]); + SubstituteExtensions.When(substituteCall: x => _ = x[{arg}], substitute: substitute); }} }} }}"; @@ -337,6 +364,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); var _ = substitute[{arg}]; substitute.When(x => _ = x[{arg}]); + SubstituteExtensions.When(substitute, x => _ = x[{arg}]); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => _ = x[{arg}]); + SubstituteExtensions.When(substituteCall: x => _ = x[{arg}], substitute: substitute); }} }} }}"; @@ -364,6 +394,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); var _ = substitute[{arg}]; substitute.When(x => _ = x[{arg}]); + SubstituteExtensions.When(substitute, x => _ = x[{arg}]); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => _ = x[{arg}]); + SubstituteExtensions.When(substituteCall: x => _ = x[{arg}], substitute: substitute); }} }} }}"; @@ -465,6 +498,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}); substitute.When(x => x.Bar({arg})); + SubstituteExtensions.When(substitute, x => x.Bar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar({arg})); + SubstituteExtensions.When(substituteCall: x => x.Bar({arg}), substitute: substitute); }} }} }}"; @@ -565,6 +601,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.FooBar({arg}); substitute.When(x => x.FooBar({arg})); + SubstituteExtensions.When(substitute, x => x.FooBar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.FooBar({arg})); + SubstituteExtensions.When(substituteCall: x => x.FooBar({arg}), substitute: substitute); }} }} }}"; @@ -603,6 +642,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.FooBar({arg}); substitute.When(x => x.FooBar({arg})); + SubstituteExtensions.When(substitute, x => x.FooBar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.FooBar({arg})); + SubstituteExtensions.When(substituteCall: x => x.FooBar({arg}), substitute: substitute); }} }} }}"; @@ -639,6 +681,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.FooBar({arg}); substitute.When(x => x.FooBar({arg})); + SubstituteExtensions.When(substitute, x => x.FooBar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.FooBar({arg})); + SubstituteExtensions.When(substituteCall: x => x.FooBar({arg}), substitute: substitute); }} }} }}"; @@ -673,6 +718,9 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.FooBar({arg}); substitute.When(x => x.FooBar({arg})); + SubstituteExtensions.When(substitute, x => x.FooBar({arg})); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.FooBar({arg})); + SubstituteExtensions.When(substituteCall: x => x.FooBar({arg}), substitute: substitute); }} }} }}"; @@ -804,7 +852,13 @@ public void Test() {{ var substitute = Substitute.For(); substitute.{whenMethod}(x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substitute, x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substitute: substitute, substituteCall: x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substituteCall: x => _ = x.Bar = {arg}, substitute: substitute); substitute.{whenMethod}(x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substitute, x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substitute: substitute, substituteCall: x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substituteCall: x => x[1] = {arg}, substitute: substitute); }} }} }}"; @@ -832,7 +886,13 @@ public void Test() {{ var substitute = Substitute.For(); substitute.{whenMethod}(x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substitute, x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substitute: substitute, substituteCall: x => _ = x.Bar = {arg}); + SubstituteExtensions.{whenMethod}(substituteCall: x => _ = x.Bar = {arg}, substitute: substitute); substitute.{whenMethod}(x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substitute, x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substitute: substitute, substituteCall: x => x[1] = {arg}); + SubstituteExtensions.{whenMethod}(substituteCall: x => x[1] = {arg}, substitute: substitute); }} }} }}"; @@ -893,12 +953,26 @@ public void Test() } [CombinatoryData( - "Received(Quantity.None())", - "Received()", - "ReceivedWithAnyArgs(Quantity.None())", - "ReceivedWithAnyArgs()", - "DidNotReceive()", - "DidNotReceiveWithAnyArgs()")] + "substitute.Received(Quantity.None())", + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", + "substitute.Received()", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", + "substitute.ReceivedWithAnyArgs(Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", + "substitute.ReceivedWithAnyArgs()", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", + "substitute.DidNotReceive()", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", + "substitute.DidNotReceiveWithAnyArgs()", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)")] public override async Task ReportsDiagnostics_WhenAssigningInvalidArgMatchersToMemberPrecededByWithAnyArgsLikeMethod(string receivedMethod, string arg) { var source = $@"using System; @@ -918,8 +992,8 @@ public class FooTests public void Test() {{ var substitute = Substitute.For(); - substitute.{receivedMethod}.Foo = {arg}; - substitute.{receivedMethod}[1] = {arg}; + {receivedMethod}.Foo = {arg}; + {receivedMethod}[1] = {arg}; }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs index 56cde3a9..ae6d67f5 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -925,6 +925,7 @@ public void Test() {{ int i = 0; var substitute = NSubstitute.Substitute.For(); + {method}(substitute, {call}).Do(callInfo => i++); {method}(substitute: substitute, substituteCall: {call}).Do(callInfo => i++); {method}(substituteCall: {call}, substitute: substitute).Do(callInfo => i++); }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 6f524dec..702e7c19 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -5,17 +5,33 @@ namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.ReceivedInR [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)")] public class ReceivedAsOrdinaryMethodTests : ReceivedInReceivedInOrderDiagnosticVerifier { public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForMethod(string method) @@ -237,6 +253,9 @@ private static string GetPlainMethodName(string methodName) { var plainMethodName = methodName.Replace("", string.Empty) .Replace("(substitute, Quantity.None())", string.Empty) + .Replace("(substitute: substitute, requiredQuantity: Quantity.None())", string.Empty) + .Replace("(requiredQuantity: Quantity.None(), substitute: substitute)", string.Empty) + .Replace("(substitute: substitute)", string.Empty) .Replace("(substitute)", string.Empty); var planMethodNameWithoutNamespace = From 700749a07f34ef5711e28ac5c400ee47646ff4eb Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 23:56:10 +0200 Subject: [PATCH 21/35] GH-153 - adding missing test cases for out of order parameters --- ...gumentsForInterfaceCodeFixProviderTests.cs | 9 + ...dForUnsupportedTypeCodeFixProviderTests.cs | 8 + .../DoMethodPrecededByOrdinaryMethodTests.cs | 64 ++++++ .../ThrowsAsOrdinaryMethodTests.cs | 165 ++++++++++++++++ .../ReturnsAsOrdinaryMethodTests.cs | 57 +++++- .../ForAsGenericMethodTests.cs | 7 + .../ForAsNonGenericMethodTests.cs | 69 ++++++- .../SubstituteFactoryCreateMethodTests.cs | 49 ++++- ...bstituteFactoryCreatePartialMethodTests.cs | 36 +++- .../ReceivedAsOrdinaryMethodTests.cs | 185 ++++++++++-------- .../CodeFixProviders/CodeFixVerifier.cs | 21 +- .../ReturnsAsOrdinaryMethodTests.cs | 13 +- .../ThrowsAsOrdinaryMethodTests.cs | 13 +- 13 files changed, 601 insertions(+), 95 deletions(-) diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs index e7fbb56f..0b4ceec3 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs @@ -30,6 +30,7 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(1, 2, 3); + var otherSubstitute = NSubstitute.Substitute.For(constructorArguments: new [] { 1, 2, 3 }); } } }"; @@ -69,6 +70,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo) }, new object[] { 1 }); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) }, constructorArguments: new object[] { 1 }); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(IFoo) }); } } }"; @@ -85,6 +88,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(IFoo) }); } } }"; @@ -108,6 +113,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)}, new object[] { 1 }); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: new object[] { 1 }); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new[] {typeof(IFoo)}); } } }"; @@ -125,6 +132,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(IFoo)}); } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs index 5744ea7c..a041004e 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs @@ -97,6 +97,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(System.Func)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(System.Func)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(System.Func)}); } } }"; @@ -110,6 +112,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(System.Func)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(System.Func)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(System.Func)}); } } }"; @@ -134,6 +138,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(IFoo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(IFoo)}); } } }"; @@ -151,6 +157,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(IFoo)}); } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs index db7d12c9..c4eb1a00 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs @@ -84,6 +84,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -123,6 +131,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -250,6 +266,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -304,6 +328,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -450,6 +482,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -530,6 +570,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -763,6 +811,14 @@ public void Test() {{ {argAccess} }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => + {{ + {argAccess} + }}); + {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => + {{ + {argAccess} + }}); }} }} }}"; @@ -916,6 +972,14 @@ public void Test() {{ callInfo[0] = 1; }}); + {method}(substitute: sub, substituteCall: substitute => {{var _ = substitute.Bar(out value); }}).Do(callInfo => + {{ + callInfo[0] = 1; + }}); + {method}(substituteCall: substitute => {{var _ = substitute.Bar(out value); }}, substitute: sub).Do(callInfo => + {{ + callInfo[0] = 1; + }}); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index 084f4880..09889a5a 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -46,6 +46,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: returnedValue, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: returnedValue); }} }} }}"; @@ -80,6 +90,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -119,6 +139,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -246,6 +276,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -300,6 +340,11 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -345,6 +390,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -397,6 +452,11 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -433,6 +493,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {callInfo}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {callInfo}); }} }} }}"; @@ -474,6 +544,11 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -508,6 +583,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -660,6 +745,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -749,6 +844,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -790,6 +895,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -828,6 +943,11 @@ public void Test() [|callInfo[1]|] = 1; return new Exception(); }}); + {method}(createException: callInfo => + {{ + [|callInfo[1]|] = 1; + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -864,6 +984,16 @@ public void Test() callInfo[0] = 1; return new Exception(); }}); + {method}(value: substitute.Bar(ref value), createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}, value: substitute.Bar(ref value)); }} }} }}"; @@ -895,6 +1025,16 @@ public void Test() callInfo[0] = 1; return new Exception(); }}); + {method}(value: substitute.Bar(out value), createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}, value: substitute.Bar(out value)); }} }} }}"; @@ -931,6 +1071,11 @@ public void Test() [|callInfo[1]|] = 1; return new Exception(); }}); + {method}(createException: callInfo => + {{ + [|callInfo[1]|] = 1; + return new Exception(); + }}, value: substitute.Bar(out value)); }} }} }}"; @@ -963,6 +1108,16 @@ public void Test() [|callInfo[0]|] = {right}; return new Exception(); }}); + {method}(value: substitute.Bar(out value), createException: callInfo => + {{ + [|callInfo[0]|] = {right}; + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + [|callInfo[0]|] = {right}; + return new Exception(); + }}, value: substitute.Bar(out value)); }} }} }}"; @@ -1001,6 +1156,16 @@ public void Test() callInfo[0] = {right}; return new Exception(); }}); + {method}(value: substitute.Bar(out value), createException: callInfo => + {{ + callInfo[0] = {right}; + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + callInfo[0] = {right}; + return new Exception(); + }}, value: substitute.Bar(out value)); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index d225c101..384475ab 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -32,6 +33,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]); + {method}(value: substitute.Bar(), returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|]); + {method}(returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|], value: substitute.Bar()); }} @@ -55,7 +58,7 @@ private int OtherReturn() { $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn())." - }; + }.Repeat(3).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -85,6 +88,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]); + {method}(value: substitute.Bar(), returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|]); + {method}(returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|], value: substitute.Bar()); }} @@ -108,7 +113,7 @@ private int OtherReturn() { $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn())." - }; + }.Repeat(3).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -138,6 +143,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]); + {method}(value: substitute.Bar(), returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|]); + {method}(returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|], value: substitute.Bar()); }} @@ -160,7 +167,7 @@ private int OtherReturn() { $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn())." - }; + }.Repeat(3).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -225,7 +232,7 @@ private int OtherNestedReturnThis() $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => NestedReturnThis())." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -256,6 +263,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), x => ReturnThis()); + {method}(value: substitute.Bar(), returnThis: x => ReturnThis()); + {method}(returnThis: x => ReturnThis(), value: substitute.Bar()); }} private int ReturnThis() @@ -311,6 +320,8 @@ public void Test() {localVariable} var substitute = Substitute.For(); {method}(substitute.Bar(), bar); + {method}(value: substitute.Bar(), returnThis: bar); + {method}(returnThis: bar, value: substitute.Bar()); }} public IBar Bar() @@ -348,6 +359,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), {rootCall}); + {method}(value: substitute.Bar(), returnThis: {rootCall}); + {method}(returnThis: {rootCall}, value: substitute.Bar()); }} private int ReturnThis() @@ -405,6 +418,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), {rootCall}); + {method}(value: substitute.Bar(), returnThis: {rootCall}); + {method}(returnThis: {rootCall}, value: substitute.Bar()); }} private int ReturnThis() @@ -456,6 +471,7 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), {firstReturn}, {secondReturn}); + {method}(value: substitute.Bar(), returnThis: {firstReturn}, returnThese: {secondReturn}); }} @@ -507,6 +523,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|FooBar.ReturnThis()|]); + {method}(value: substitute.Bar(), returnThis: [|FooBar.ReturnThis()|]); + {method}(returnThis: [|FooBar.ReturnThis()|], value: substitute.Bar()); }} }} }}"; @@ -550,6 +568,8 @@ public async Task Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|await ReturnThis()|]); + {method}(value: substitute.Bar(), returnThis: [|await ReturnThis()|]); + {method}(returnThis: [|await ReturnThis()|], value: substitute.Bar()); }} private async Task ReturnThis() @@ -584,6 +604,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), 1, {reEntrantArrayCall}); + {method}(value: substitute.Bar(), returnThis: 1, returnThese: {reEntrantArrayCall}); + {method}(returnThis: 1, returnThese: {reEntrantArrayCall}, value: substitute.Bar()); }} private int ReturnThis() @@ -622,6 +644,7 @@ public void Test() var substitute = Substitute.For(); var array = new[] {{ ReturnThis() }}; {method}(substitute.Bar(), 1, array); + {method}(value: substitute.Bar(), returnThis: 1, returnThese: array); }} private int ReturnThis() @@ -673,6 +696,8 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For(); {method}(substitute.FooBar(), typeof({type})); + {method}(value: substitute.FooBar(), returnThis: typeof({type})); + {method}(returnThis: typeof({type}), value: substitute.FooBar()); }} }} }}"; @@ -704,6 +729,8 @@ public void Test() foreach (var fooBar in new FooBar[0]) {{ {method}(substitute.Bar(), fooBar.Value); + {method}(value: substitute.Bar(), returnThis: fooBar.Value); + {method}(returnThis: fooBar.Value, value: substitute.Bar()); }} }} }} @@ -731,10 +758,20 @@ public void Test() foreach (var value in Enumerable.Empty()) {{ {method}(firstEnumerator.Current, value + 1); + {method}(value: firstEnumerator.Current, returnThis: value + 1); + {method}(returnThis: value + 1, value: firstEnumerator.Current); {method}(firstEnumerator.Current, value + 1); + {method}(value: firstEnumerator.Current, returnThis: value + 1); + {method}(returnThis: value + 1, value: firstEnumerator.Current); {method}(secondEnumerator.Current, value + 1); + {method}(value: secondEnumerator.Current, returnThis: value + 1); + {method}(returnThis: value + 1, value: secondEnumerator.Current); {method}(thirdEnumerator.Current, value + 1); + {method}(value: thirdEnumerator.Current, returnThis: value + 1); + {method}(returnThis: value + 1, value: thirdEnumerator.Current); {method}(fourthEnumerator.Current, value + 1); + {method}(value: fourthEnumerator.Current, returnThis: value + 1); + {method}(returnThis: value + 1, value: fourthEnumerator.Current); }} }} }} @@ -764,6 +801,8 @@ public void Test() var secondSubstitute = Substitute.For(); {method}(secondSubstitute.Id, [|firstSubstitute.Id|]); + {method}(value: secondSubstitute.Id, returnThis: [|firstSubstitute.Id|]); + {method}(returnThis: [|firstSubstitute.Id|], value: secondSubstitute.Id); }} }} }}"; @@ -796,6 +835,8 @@ public void Test() {{ var secondSubstitute = Substitute.For(); {method}(secondSubstitute.Id, [|firstSubstitute.Id|]); + {method}(value: secondSubstitute.Id, returnThis: [|firstSubstitute.Id|]); + {method}(returnThis: [|firstSubstitute.Id|], value: secondSubstitute.Id); }} }} }}"; @@ -825,6 +866,8 @@ public void Test() {{ var secondSubstitute = Substitute.For(); {method}(secondSubstitute.Id, [|firstSubstitute.Id|]); + {method}(value: secondSubstitute.Id, returnThis: [|firstSubstitute.Id|]); + {method}(returnThis: [|firstSubstitute.Id|], value: secondSubstitute.Id); }} }} }}"; @@ -859,7 +902,11 @@ public void Test() var value = fourthSubstitute.Id; {method}(secondSubstitute.Id, firstSubstitute.Id); + {method}(value: secondSubstitute.Id, returnThis: firstSubstitute.Id); + {method}(returnThis: firstSubstitute.Id, value: secondSubstitute.Id); {method}(secondSubstitute.Id, value); + {method}(value: secondSubstitute.Id, returnThis: value); + {method}(returnThis: value, value: secondSubstitute.Id); }} }} }}"; @@ -890,6 +937,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), _ => 1, new Func[] {{ _ => OtherReturn() }}); + {method}(value: substitute.Bar(), returnThis: _ => 1, returnThese: new Func[] {{ _ => OtherReturn() }}); + {method}(returnThis: _ => 1, returnThese: new Func[] {{ _ => OtherReturn() }}, value: substitute.Bar()); }} private int OtherReturn() diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs index 3c7b15c3..57f36a02 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs @@ -44,6 +44,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; } } }"; @@ -84,6 +85,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For>(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For>(constructorArguments: 1)|]; } } }"; @@ -213,6 +215,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; } } }"; @@ -363,6 +366,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1, 2, 3)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(new [] { 1, 2, 3 })|]; } } }"; @@ -388,6 +392,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; } } }"; @@ -413,6 +418,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; } } }"; @@ -515,6 +521,7 @@ public class FooTests public void Test() {{ var substitute = [|NSubstitute.Substitute.For({invocationValues})|]; + var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: {invocationValues})|]; }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs index 27f68482..12f22257 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.SubstituteAnalyzerTests; @@ -21,6 +23,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(IFoo) }); } } }"; @@ -44,6 +48,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo) }, new object[] { }); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) }, constructorArguments: new object[] { }); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: new object[] { }, typesToProxy: new [] { typeof(IFoo) }); } } }"; @@ -67,6 +73,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(IFoo) }, new object[] { 1 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(IFoo) })|]; } } }"; @@ -89,6 +97,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(Func) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Func) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Func) }); } } }"; @@ -107,11 +117,24 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Func) }, new object[] { 1 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Func) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Func) })|]; } } }"; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForDelegateDescriptor, "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(new [] { typeof(Func) },null) instead."); - } + var textParserResult = TextParser.GetSpans(source); + + // TODO + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(new [] { typeof(Func) },null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Func) },null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(constructorArguments: new object[] { 1 },null)" + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForDelegateDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); + } [Theory] [InlineData("new [] { typeof(Bar), new Foo().GetType() }")] @@ -136,6 +159,8 @@ public void Test() {{ var bar = new Bar(); var substitute = NSubstitute.Substitute.For({proxyExpression}, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: {proxyExpression}, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: {proxyExpression}); }} }} }}"; @@ -163,6 +188,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo), typeof(Bar) }, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo), typeof(Bar) }, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo), typeof(Bar) })|]; } } }"; @@ -185,6 +212,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(Foo), typeof(Foo) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo), typeof(Foo) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo), typeof(Foo) }); } } }"; @@ -212,6 +241,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo), typeof(IBar) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo), typeof(IBar) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(IFoo), typeof(IBar) }); } } }"; @@ -239,6 +270,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(IFoo), typeof(Bar) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo), typeof(Bar) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(IFoo), typeof(Bar) }); } } }"; @@ -266,6 +299,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(IFoo), typeof(Bar) }, new object[] { 1 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo), typeof(Bar) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(IFoo), typeof(Bar) })|]; } } }"; @@ -292,6 +327,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -316,6 +353,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -340,6 +379,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -366,6 +407,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(Foo) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -392,6 +435,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(new [] { typeof(Foo) }, null); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -417,6 +462,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, new object[] { 1, 2, 3 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1, 2, 3 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1, 2, 3 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -442,6 +489,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, new object[] { 1 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -467,6 +516,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, new object[] { 1 })|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -488,6 +539,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(new [] { typeof(Foo) }, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(Foo) })|]; } } }"; @@ -510,6 +563,8 @@ public class FooTests public void Test() {{ var substitute = NSubstitute.Substitute.For(new [] {{ typeof(Foo) }}, null ); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] {{ typeof(Foo) }}, constructorArguments: null ); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] {{ typeof(Foo) }}); }} }} }}"; @@ -532,6 +587,8 @@ public class FooTests public void Test() {{ var substitute = [|NSubstitute.Substitute.For(new [] {{ typeof(Foo) }}, null)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] {{ typeof(Foo) }}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: null, typesToProxy: new [] {{ typeof(Foo) }})|]; }} }} }}"; @@ -566,6 +623,8 @@ public class FooTests public void Test() {{ var substitute = [|NSubstitute.Substitute.For(new [] {{ typeof(Foo) }}, new object[] {{{invocationValues}}})|]; + var otherSubstitute = [|NSubstitute.Substitute.For(typesToProxy: new [] {{ typeof(Foo) }}, constructorArguments: new object[] {{{invocationValues}}})|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new object[] {{{invocationValues}}}, typesToProxy: new [] {{ typeof(Foo) }})|]; }} }} }}"; @@ -601,7 +660,7 @@ public class FooTests {{ public void Test() {{ - var substitute = NSubstitute.Substitute.For(new [] {{ typeof(Foo) }}, {invocationValues}); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: {invocationValues}, typesToProxy: new [] {{ typeof(Foo) }}); }} }} }}"; @@ -618,6 +677,8 @@ public class FooTests { public T Foo() where T : class { + Substitute.For(typesToProxy: new [] { typeof(T)}, constructorArguments: null); + Substitute.For(constructorArguments: null, typesToProxy: new [] { typeof(T)}); return (T)Substitute.For(new [] { typeof(T)}, null); } } diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs index 25b4a046..a8ad26bf 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs @@ -22,6 +22,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(IFoo)}); } } }"; @@ -46,6 +48,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)}, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)}, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new[] {typeof(IFoo)})|]; } } }"; @@ -70,6 +74,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Func)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Func)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Func)}); } } }"; @@ -93,6 +99,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Func)}, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Func)}, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new[] {typeof(Func)})|]; } } }"; @@ -119,6 +127,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(Foo), typeof(Bar)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(Foo), typeof(Bar)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new [] { typeof(Foo), typeof(Bar)})|]; } } }"; @@ -141,6 +151,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(Foo), typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(Foo), typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new [] { typeof(Foo), typeof(Foo)}); } } }"; @@ -168,6 +180,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(IFoo), typeof(IBar)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(IFoo), typeof(IBar)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new [] { typeof(IFoo), typeof(IBar)}); } } @@ -197,6 +211,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(IFoo), typeof(Bar) }, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(IFoo), typeof(Bar) }, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new [] { typeof(IFoo), typeof(Bar) }); } } }"; @@ -224,6 +240,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(IFoo), typeof(Bar) }, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(IFoo), typeof(Bar) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(IFoo), typeof(Bar) })|]; } } }"; @@ -249,6 +267,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)})|]; } } }"; @@ -273,6 +293,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)})|]; } } }"; @@ -297,6 +319,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)})|]; } } }"; @@ -323,6 +347,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -349,6 +375,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -374,6 +402,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, new object[]{ 1, 2, 3})|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: new object[]{ 1, 2, 3})|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[]{ 1, 2, 3}, typesToProxy: new[] {typeof(Foo)})|]; } } }"; @@ -400,6 +430,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, new object[]{ 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: new object[]{ 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[]{ 1 }, typesToProxy: new[] {typeof(Foo)})|]; } } }"; @@ -427,6 +459,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, new object[]{ 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: new object[]{ 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[]{ 1 }, typesToProxy: new[] {typeof(Foo)} )|]; } } }"; @@ -449,6 +483,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)})|]; } } } @@ -474,6 +510,8 @@ public class FooTests public void Test() {{ var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {{typeof(Foo)}}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {{typeof(Foo)}}); }} }} }}"; @@ -498,6 +536,8 @@ public class FooTests public void Test() {{ var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {{typeof(Foo)}}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {{typeof(Foo)}})|]; }} }} }}"; @@ -534,6 +574,8 @@ public class FooTests public void Test() {{ var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new[] {{typeof(Foo)}}, new object[] {{{invocationValues}}})|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: new object[] {{{invocationValues}}})|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] {{{invocationValues}}}, typesToProxy: new[] {{typeof(Foo)}})|]; }} }} }}"; @@ -572,6 +614,8 @@ public class FooTests public void Test() {{ var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {{typeof(Foo)}}, {invocationValues}); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: {invocationValues}); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: {invocationValues}, typesToProxy: new[] {{typeof(Foo)}}); }} }} }}"; @@ -591,7 +635,10 @@ public class FooTests { public T Foo() where T : class { - return (T) SubstitutionContext.Current.SubstituteFactory.Create(new Type[] {typeof(T)}, null); + var substitute = (T)SubstitutionContext.Current.SubstituteFactory.Create(new Type[] {typeof(T)}, null); + var otherSubstitute = (T)SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new Type[] {typeof(T)}, constructorArguments: null); + var yetAnotherSubstitute = (T)SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new Type[] {typeof(T)}); + return substitute; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs index d503ae46..e92375b2 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -22,6 +22,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(IFoo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(IFoo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(IFoo)})|]; } } }"; @@ -45,6 +47,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Func)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Func)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Func)})|]; } } }"; @@ -71,6 +75,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -96,6 +102,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -121,6 +129,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -148,6 +158,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)}); } } }"; @@ -175,6 +187,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)}); } } }"; @@ -201,6 +215,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, new object[] { 1, 2, 3})|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: new object[] { 1, 2, 3})|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] { 1, 2, 3}, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -227,6 +243,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] { 1 }, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -254,6 +272,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] { 1 }, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -277,6 +297,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Foo)}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Foo)}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Foo)})|]; } } }"; @@ -302,6 +324,8 @@ public class FooTests public void Test() {{ var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] {{ typeof(Foo)}}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] {{ typeof(Foo)}}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] {{ typeof(Foo)}}); }} }} }}"; @@ -327,6 +351,8 @@ public class FooTests public void Test() {{ var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] {{ typeof(Foo)}}, null)|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] {{ typeof(Foo)}}, constructorArguments: null)|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] {{ typeof(Foo)}})|]; }} }} }}"; @@ -363,6 +389,8 @@ public class FooTests public void Test() {{ var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {{typeof(Foo)}}, new object[] {{{invocationValues}}})|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: new object[] {{{invocationValues}}})|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] {{{invocationValues}}}, typesToProxy: new[] {{typeof(Foo)}})|]; }} }} }}"; @@ -401,6 +429,8 @@ public class FooTests public void Test() {{ var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {{typeof(Foo)}}, {invocationValues}); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {{typeof(Foo)}}, constructorArguments: {invocationValues}); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: {invocationValues}, typesToProxy: new[] {{typeof(Foo)}}); }} }} }}"; @@ -420,7 +450,11 @@ public class FooTests { public T Foo() where T : class { - return (T) SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] {typeof(T)}, null); + var substitute = (T)SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] {typeof(T)}, null); + var otherSubstitute = (T)SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] {typeof(T)}, constructorArguments: null); + var yetAnotherSubstitute = (T)SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] {typeof(T)}); + + return substitute; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 4075414f..a773f129 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -1,33 +1,47 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.UnusedReceivedAnalyzerTests; - -[CombinatoryData( - "ReceivedExtensions.Received(substitute, Quantity.None())", - "ReceivedExtensions.Received(substitute, Quantity.None())", - "SubstituteExtensions.Received(substitute)", - "SubstituteExtensions.Received(substitute)", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceive(substitute)", - "SubstituteExtensions.DidNotReceive(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)")] -public class ReceivedAsOrdinaryMethodTests : UnusedReceivedDiagnosticVerifier +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.UnusedReceivedAnalyzerTests { - public override async Task ReportDiagnostics_WhenUsedWithoutMemberCall(string method) + [CombinatoryData( + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)")] + public class ReceivedAsOrdinaryMethodTests : UnusedReceivedDiagnosticVerifier { - var plainMethodName = method.Replace("", string.Empty) - .Replace("(substitute, Quantity.None())", string.Empty) - .Replace("(substitute)", string.Empty); + public override async Task ReportDiagnostics_WhenUsedWithoutMemberCall(string method) + { + var plainMethodName = method.Replace("", string.Empty) + .Replace("(substitute, Quantity.None())", string.Empty) + .Replace("(substitute)", string.Empty); - var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) - .Replace("ReceivedExtensions.", string.Empty); + var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) + .Replace("ReceivedExtensions.", string.Empty); - var source = $@"using NSubstitute; + var source = $@"using NSubstitute; using NSubstitute.ReceivedExtensions; namespace MyNamespace {{ @@ -45,12 +59,12 @@ public void Test() }} }}"; - await VerifyDiagnostic(source, Descriptor, $@"Unused received check. To fix, make sure there is a call after ""{planMethodNameWithoutNamespace}"". Correct: ""{plainMethodName}(sub).SomeCall();"". Incorrect: ""{plainMethodName}(sub);"""); - } + await VerifyDiagnostic(source, Descriptor, $@"Unused received check. To fix, make sure there is a call after ""{planMethodNameWithoutNamespace}"". Correct: ""{plainMethodName}(sub).SomeCall();"". Incorrect: ""{plainMethodName}(sub);"""); + } - public override async Task ReportNoDiagnostics_WhenUsedWithMethodMemberAccess(string method) - { - var source = $@"using NSubstitute; + public override async Task ReportNoDiagnostics_WhenUsedWithMethodMemberAccess(string method) + { + var source = $@"using NSubstitute; using NSubstitute.ReceivedExtensions; namespace MyNamespace @@ -74,12 +88,12 @@ public void Test() }} }}"; - await VerifyNoDiagnostic(source); - } + await VerifyNoDiagnostic(source); + } - public override async Task ReportNoDiagnostics_WhenUsedWithPropertyMemberAccess(string method) - { - var source = $@"using NSubstitute; + public override async Task ReportNoDiagnostics_WhenUsedWithPropertyMemberAccess(string method) + { + var source = $@"using NSubstitute; using NSubstitute.ReceivedExtensions; namespace MyNamespace @@ -100,12 +114,12 @@ public void Test() }} }}"; - await VerifyNoDiagnostic(source); - } + await VerifyNoDiagnostic(source); + } - public override async Task ReportNoDiagnostics_WhenUsedWithIndexerMemberAccess(string method) - { - var source = $@"using NSubstitute; + public override async Task ReportNoDiagnostics_WhenUsedWithIndexerMemberAccess(string method) + { + var source = $@"using NSubstitute; using NSubstitute.ReceivedExtensions; namespace MyNamespace {{ @@ -125,25 +139,41 @@ public void Test() }} }}"; - await VerifyNoDiagnostic(source); - } - - [CombinatoryData( - "ReceivedExtensions.Received(substitute, Quantity.None())", - "ReceivedExtensions.Received>(substitute, Quantity.None())", - "SubstituteExtensions.Received(substitute)", - "SubstituteExtensions.Received>(substitute)", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "ReceivedExtensions.ReceivedWithAnyArgs>(substitute, Quantity.None())", - "SubstituteExtensions.ReceivedWithAnyArgs>(substitute)", - "SubstituteExtensions.DidNotReceive(substitute)", - "SubstituteExtensions.DidNotReceive>(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs>(substitute)")] - public override async Task ReportNoDiagnostics_WhenUsedWithInvokingDelegate(string method) - { - var source = $@"using System; + await VerifyNoDiagnostic(source); + } + + [CombinatoryData( + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity: Quantity.None(), substitute: substitute)", + "ReceivedExtensions.Received>(substitute, Quantity.None())", + "ReceivedExtensions.Received>(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.Received>(requiredQuantity: Quantity.None(), substitute: substitute)", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute: substitute)", + "SubstituteExtensions.Received>(substitute)", + "SubstituteExtensions.Received>(substitute: substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity: Quantity.None(), substitute: substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs>(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs>(substitute: substitute, requiredQuantity: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs>(requiredQuantity: Quantity.None(), substitute: substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs>(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs>(substitute: substitute)", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute: substitute)", + "SubstituteExtensions.DidNotReceive>(substitute)", + "SubstituteExtensions.DidNotReceive>(substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs>(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs>(substitute: substitute)")] + public override async Task ReportNoDiagnostics_WhenUsedWithInvokingDelegate(string method) + { + var source = $@"using System; using NSubstitute; using NSubstitute.ReceivedExtensions; @@ -158,25 +188,25 @@ public void Test() }} }} }}"; - await VerifyNoDiagnostic(source); - } - - [CombinatoryData( - "ReceivedExtensions.Received(substitute, Quantity.None())", - "ReceivedExtensions.Received(substitute, Quantity.None())", - "SubstituteExtensions.Received(substitute, 1, 1)", - "SubstituteExtensions.Received(substitute, 1, 1)", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)")] - public override async Task ReportsNoDiagnostics_WhenUsedWithUnfortunatelyNamedMethod(string method) - { - var source = $@"using System; + await VerifyNoDiagnostic(source); + } + + [CombinatoryData( + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute, Quantity.None())", + "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute, 1, 1)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)")] + public override async Task ReportsNoDiagnostics_WhenUsedWithUnfortunatelyNamedMethod(string method) + { + var source = $@"using System; namespace NSubstitute {{ @@ -244,6 +274,7 @@ public void Test() }} }} }}"; - await VerifyNoDiagnostic(source); + await VerifyNoDiagnostic(source); + } } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs index 5953d621..911b3224 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -31,6 +32,7 @@ protected async Task VerifyFix( NSubstituteVersion version = NSubstituteVersion.Latest) { using var workspace = new AdhocWorkspace(); + codeFixIndex ??= 0; var project = AddProject(workspace.CurrentSolution, oldSource); project = UpdateNSubstituteMetadataReference(project, version); @@ -60,12 +62,18 @@ protected async Task VerifyFix( break; } - document = await document.ApplyCodeAction(actions[codeFixIndex ?? 0]); + document = await document.ApplyCodeAction(actions[codeFixIndex.Value]); compilation = await document.Project.GetCompilationAsync(); compilerDiagnostics = compilation.GetDiagnostics(); - VerifyNoCompilerDiagnosticErrors(compilerDiagnostics); + var compilationErrorDiagnostics = GetCompilationErrorDiagnostics(compilerDiagnostics); + + if (compilationErrorDiagnostics.Any()) + { + Execute.Assertion.Fail( + $"Fix {codeFixIndex} for diagnostic {analyzerDiagnostics[i].ToString()} introduced compilation error(s): {compilationErrorDiagnostics.ToDebugString()} New document:{Environment.NewLine}{await document.ToFullString()}"); + } analyzerDiagnostics = await compilation.GetSortedAnalyzerDiagnostics( DiagnosticAnalyzer, @@ -86,4 +94,13 @@ protected async Task VerifyFix( actual.Should().Be(newSource); } + + protected static IReadOnlyList GetCompilationErrorDiagnostics(ImmutableArray diagnostics) + { + var compilationErrorDiagnostics = diagnostics.Where(diagnostic => + diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error) + .ToList(); + + return compilationErrorDiagnostics; + } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 21de9563..b44f3060 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq.Extensions; using NSubstitute.Analyzers.Shared; using NSubstitute.Analyzers.Shared.Settings; using NSubstitute.Analyzers.Tests.Shared.Extensibility; @@ -768,6 +769,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], 1) + {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) {method}([|substituteFooBarBar.FooBar()|], 1) End Sub @@ -782,7 +785,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -833,6 +836,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar(Of Integer))() {method}([|substituteFooBarBar(1)|], 1) + {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) {method}([|substituteFooBarBar.FooBar()|], 1) End Sub @@ -847,7 +852,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -901,6 +906,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], 1) + {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) {method}([|substituteFooBarBar.FooBar()|], 1) End Sub @@ -915,7 +922,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index 8b37df7c..f2d9deb7 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq.Extensions; using NSubstitute.Analyzers.Shared; using NSubstitute.Analyzers.Shared.Settings; using NSubstitute.Analyzers.Tests.Shared.Extensibility; @@ -860,6 +861,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], New Exception()) + {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) {method}([|substituteFooBarBar.FooBar()|], New Exception()) End Sub @@ -874,7 +877,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -928,6 +931,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar(Of Integer))() {method}([|substituteFooBarBar(1)|], New Exception()) + {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) {method}([|substituteFooBarBar.FooBar()|], New Exception()) End Sub @@ -942,7 +947,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -999,6 +1004,8 @@ Public Sub Test() Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], New Exception()) + {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) {method}([|substituteFooBarBar.FooBar()|], New Exception()) End Sub @@ -1013,7 +1020,7 @@ End Namespace "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }; + }.Repeat(2).ToList(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); From f72f076e112c24db07d9a06ae1b50ebb712e74ca Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 30 Aug 2022 23:58:13 +0200 Subject: [PATCH 22/35] GH-153 - adding missing test cases for out of order parameters --- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 14 +- .../SubstituteProxyAnalysis.cs | 2 +- .../DiagnosticAnalyzers/SubstituteAnalyzer.cs | 17 +- ...gumentsForInterfaceCodeFixProviderTests.cs | 1 + .../ForAsGenericMethodTests.cs | 8 +- .../ForAsNonGenericMethodTests.cs | 25 ++- .../ForPartsOfMethodTests.cs | 5 + .../SubstituteFactoryCreateMethodTests.cs | 26 ++- ...bstituteFactoryCreatePartialMethodTests.cs | 26 ++- .../ReceivedAsOrdinaryMethodTests.cs | 5 +- .../DiagnosticAnalyzers/DiagnosticVerifier.cs | 20 +-- ...gumentsForInterfaceCodeFixProviderTests.cs | 10 ++ ...dForUnsupportedTypeCodeFixProviderTests.cs | 8 + .../ReturnsAsOrdinaryMethodTests.cs | 52 +++++- .../ThrowsAsOrdinaryMethodTests.cs | 54 +++++- .../ReturnsAsOrdinaryMethodTests.cs | 62 ++++++- .../ReceivedAsOrdinaryMethodTests.cs | 166 ++++++++++-------- .../ForAsGenericMethodTests.cs | 6 + .../ForAsNonGenericMethodTests.cs | 78 +++++++- .../ForPartsOfMethodTests.cs | 3 + .../SubstituteFactoryCreateMethodTests.cs | 71 +++++++- ...bstituteFactoryCreatePartialMethodTests.cs | 51 +++++- 22 files changed, 590 insertions(+), 120 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs index 4a1c0f37..9da55dc8 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -37,8 +37,18 @@ protected override SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutCons } else { - var nullSyntax = Argument(LiteralExpression(SyntaxKind.NullLiteralExpression)); - argumentListSyntax = ArgumentList(SeparatedList(invocationExpressionSyntax.ArgumentList.Arguments.Take(1)).Add(nullSyntax)); + var arguments = invocationOperation.Arguments.Select(argumentOperation => + { + var argumentSyntax = (ArgumentSyntax)argumentOperation.Syntax; + if (argumentOperation.Parameter.Ordinal > 0) + { + argumentSyntax = argumentSyntax.WithExpression(LiteralExpression(SyntaxKind.NullLiteralExpression)); + } + + return argumentSyntax; + }); + + argumentListSyntax = ArgumentList(SeparatedList(arguments)); } return invocationExpressionSyntax.WithArgumentList(argumentListSyntax); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs index ad8a8b61..c491d805 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs @@ -44,7 +44,7 @@ public ImmutableArray GetProxySymbols(IInvocationOperation invocati private IArrayInitializerOperation GetArrayInitializerArguments(IInvocationOperation invocationOperation) { - return invocationOperation.Arguments.FirstOrDefault()?.Value switch + return invocationOperation.Arguments.FirstOrDefault(arg => arg.Parameter.Ordinal == 0)?.Value switch { IArrayCreationOperation operation => operation.Initializer, _ => null diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs index 74baac8a..61b74525 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteAnalyzer.cs @@ -37,8 +37,21 @@ protected override SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutCons } else { - var nullSyntax = SimpleArgument(LiteralExpression(SyntaxKind.NothingLiteralExpression, Token(SyntaxKind.NothingKeyword))); - argumentListSyntax = ArgumentList(SeparatedList(invocationExpressionSyntax.ArgumentList.Arguments.Take(1)).Add(nullSyntax)); + var arguments = invocationOperation.Arguments + .OrderBy(x => x.Syntax.GetLocation().GetLineSpan().StartLinePosition.Character) + .Select(argumentOperation => + { + var argumentSyntax = (SimpleArgumentSyntax)argumentOperation.Syntax; + if (argumentOperation.Parameter.Ordinal > 0) + { + argumentSyntax = argumentSyntax.WithExpression( + LiteralExpression(SyntaxKind.NothingLiteralExpression, Token(SyntaxKind.NothingKeyword))); + } + + return argumentSyntax; + }); + + argumentListSyntax = ArgumentList(SeparatedList(arguments)); } return invocationExpressionSyntax.WithArgumentList(argumentListSyntax); diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs index 0b4ceec3..97fedd16 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs @@ -47,6 +47,7 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(); + var otherSubstitute = NSubstitute.Substitute.For(); } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs index 57f36a02..19bb6e70 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs @@ -45,6 +45,7 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(new [] { 1 })|]; } } }"; @@ -86,6 +87,7 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For>(1)|]; var otherSubstitute = [|NSubstitute.Substitute.For>(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For>(new [] { 1 })|]; } } }"; @@ -216,6 +218,7 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(new [] { 1 })|]; } } }"; @@ -367,6 +370,7 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For(1, 2, 3)|]; var otherSubstitute = [|NSubstitute.Substitute.For(new [] { 1, 2, 3 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new [] { 1, 2, 3 })|]; } } }"; @@ -393,6 +397,8 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(new [] { 1 })|]; + var yetYetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new [] { 1 })|]; } } }"; @@ -419,6 +425,7 @@ public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(new [] { 1 })|]; } } }"; @@ -521,7 +528,6 @@ public class FooTests public void Test() {{ var substitute = [|NSubstitute.Substitute.For({invocationValues})|]; - var otherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: {invocationValues})|]; }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs index 12f22257..6705c746 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs @@ -78,7 +78,17 @@ public void Test() } } }"; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForInterfaceDescriptor, "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.For(new [] { typeof(IFoo) },null) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.For(new [] { typeof(IFoo) },null) instead.", + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.For(typesToProxy: new [] { typeof(IFoo) },constructorArguments: null) instead.", + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.For(constructorArguments: null,typesToProxy: new [] { typeof(IFoo) }) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForInterfaceDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -124,17 +134,16 @@ public void Test() }"; var textParserResult = TextParser.GetSpans(source); - // TODO var diagnosticMessages = new[] - { - "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(new [] { typeof(Func) },null) instead.", - "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Func) },null) instead.", - "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(constructorArguments: new object[] { 1 },null)" - }; + { + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(new [] { typeof(Func) },null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(typesToProxy: new [] { typeof(Func) },constructorArguments: null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.For(constructorArguments: null,typesToProxy: new [] { typeof(Func) }) instead." + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForDelegateDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); - } + } [Theory] [InlineData("new [] { typeof(Bar), new Foo().GetType() }")] diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs index ca7a0790..a31167a3 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs @@ -195,6 +195,7 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.ForPartsOf(1, 2, 3)|]; + var otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: new [] { 1, 2, 3 })|]; } } }"; @@ -220,6 +221,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.ForPartsOf(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: new [] { 1 })|]; } } }"; @@ -245,6 +248,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.ForPartsOf(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: 1)|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: new [] { 1 })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs index a8ad26bf..ad8b4e67 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.SubstituteAnalyzerTests; @@ -54,7 +56,17 @@ public void Test() } }"; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForInterfaceDescriptor, "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)},null) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(IFoo)},null) instead.", + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(IFoo)},constructorArguments: null) instead.", + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null,typesToProxy: new[] {typeof(IFoo)}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForInterfaceDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -104,7 +116,17 @@ public void Test() } } }"; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForDelegateDescriptor, "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Func)},null) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Func)},null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Func)},constructorArguments: null) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null,typesToProxy: new[] {typeof(Func)}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForDelegateDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs index e92375b2..eb82cf51 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.SubstituteAnalyzerTests; @@ -27,7 +29,17 @@ public void Test() } } }"; - await VerifyDiagnostic(source, PartialSubstituteForUnsupportedTypeDescriptor, "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(new Type[] { typeof(IFoo)}, null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(IFoo)}, null) here."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(new Type[] { typeof(IFoo)}, null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(IFoo)}, null) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new Type[] { typeof(IFoo)}, constructorArguments: null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(IFoo)}, constructorArguments: null) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new Type[] { typeof(IFoo)}) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(IFoo)}) here.", + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(PartialSubstituteForUnsupportedTypeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -52,7 +64,17 @@ public void Test() } } }"; - await VerifyDiagnostic(source, PartialSubstituteForUnsupportedTypeDescriptor, "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(new Type[] { typeof(Func)}, null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Func)}, null) here."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(new Type[] { typeof(Func)}, null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(new Type[] { typeof(Func)}, null) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new Type[] { typeof(Func)}, constructorArguments: null) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new Type[] { typeof(Func)}, constructorArguments: null) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new Type[] { typeof(Func)}) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new Type[] { typeof(Func)}) here.", + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(PartialSubstituteForUnsupportedTypeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index a773f129..fb4f1c44 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -36,7 +36,10 @@ public override async Task ReportDiagnostics_WhenUsedWithoutMemberCall(string me { var plainMethodName = method.Replace("", string.Empty) .Replace("(substitute, Quantity.None())", string.Empty) - .Replace("(substitute)", string.Empty); + .Replace("(substitute)", string.Empty) + .Replace("(substitute: substitute)", string.Empty) + .Replace("(substitute: substitute, requiredQuantity: Quantity.None())", string.Empty) + .Replace("(requiredQuantity: Quantity.None(), substitute: substitute)", string.Empty); var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) .Replace("ReceivedExtensions.", string.Empty); diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticVerifier.cs index a7a54247..b667cc8b 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/DiagnosticVerifier.cs @@ -91,21 +91,19 @@ protected Diagnostic CreateDiagnostic(DiagnosticDescriptor descriptor, LinePosit private async Task VerifyDiagnosticsInternal(string[] sources, Diagnostic[] expectedDiagnostics) { - using (var workspace = new AdhocWorkspace()) - { - var project = AddProject( - workspace.CurrentSolution, - sources); + using var workspace = new AdhocWorkspace(); + var project = AddProject( + workspace.CurrentSolution, + sources); - var compilation = await project.GetCompilationAsync(); + var compilation = await project.GetCompilationAsync(); - var compilerDiagnostics = compilation.GetDiagnostics(); - VerifyNoCompilerDiagnosticErrors(compilerDiagnostics); + var compilerDiagnostics = compilation.GetDiagnostics(); + VerifyNoCompilerDiagnosticErrors(compilerDiagnostics); - var diagnostics = await compilation.GetSortedAnalyzerDiagnostics(DiagnosticAnalyzer, project.AnalyzerOptions); + var diagnostics = await compilation.GetSortedAnalyzerDiagnostics(DiagnosticAnalyzer, project.AnalyzerOptions); - VerifyDiagnosticResults(diagnostics, ImmutableArray.Create(expectedDiagnostics)); - } + VerifyDiagnosticResults(diagnostics, ImmutableArray.Create(expectedDiagnostics)); } private static void VerifyDiagnosticResults(ImmutableArray actualResults, ImmutableArray expectedResults) diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs index 3f3e28a5..f04f2170 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs @@ -26,6 +26,7 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)(1, 2, 3) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)(New Integer() { 1, 2, 3 }) End Sub End Class End Namespace @@ -39,6 +40,7 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() End Sub End Class End Namespace @@ -59,6 +61,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo)}, New Object() {1}) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= New Object() {1}) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -72,6 +76,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -92,6 +98,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, New Object() {1}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= New Object() {1}) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -106,6 +114,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs index 20154762..e6305863 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests/PartialSubstituteUsedForUnsupportedTypeCodeFixProviderTests.cs @@ -84,6 +84,8 @@ Namespace MyNamespace Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(System.Func(Of Integer))}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(System.Func(Of Integer))}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(System.Func(Of Integer))}) End Sub End Class End Namespace @@ -95,6 +97,8 @@ Namespace MyNamespace Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(System.Func(Of Integer))}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(System.Func(Of Integer))}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(System.Func(Of Integer))}) End Sub End Class End Namespace @@ -116,6 +120,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(IFoo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace"; @@ -130,6 +136,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index b44f3060..2affc70d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -764,15 +764,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute(1), 1) + {method}(value:= substitute(1), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute(1)) {method}(substitute.Bar, 1) + {method}(value:= substitute.Bar, returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.Bar) {method}(substitute.FooBar(), 1) + {method}(value:= substitute.FooBar(), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], 1) {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) + {method}(value:= [|substituteFooBarBar.Bar|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], 1) + {method}(value:= [|substituteFooBarBar.FooBar()|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -783,9 +793,15 @@ End Namespace var diagnosticMessages = new[] { "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -831,15 +847,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo(Of Integer))() {method}(substitute(1), 1) + {method}(value:= substitute(1), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute(1)) {method}(substitute.Bar, 1) + {method}(value:= substitute.Bar, returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.Bar) {method}(substitute.FooBar(), 1) + {method}(value:= substitute.FooBar(), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar(Of Integer))() {method}([|substituteFooBarBar(1)|], 1) {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) + {method}(value:= [|substituteFooBarBar.Bar|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], 1) + {method}(value:= [|substituteFooBarBar.FooBar()|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -850,9 +876,15 @@ End Namespace var diagnosticMessages = new[] { "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -901,15 +933,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute(1), 1) + {method}(value:= substitute(1), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute(1)) {method}(substitute.Bar, 1) + {method}(value:= substitute.Bar, returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.Bar) {method}(substitute.FooBar(), 1) + {method}(value:= substitute.FooBar(), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], 1) {method}(value:= [|substituteFooBarBar(1)|], returnThis:= 1) {method}(returnThis:= 1, value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], 1) + {method}(value:= [|substituteFooBarBar.Bar|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], 1) + {method}(value:= [|substituteFooBarBar.FooBar()|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -920,7 +962,13 @@ End Namespace var diagnosticMessages = new[] { "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." }.Repeat(2).ToList(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index f2d9deb7..962d945d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -856,15 +856,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute(1), New Exception()) + {method}(value:= substitute(1), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute(1)) {method}(substitute.Bar, New Exception()) + {method}(value:= substitute.Bar, ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.Bar) {method}(substitute.FooBar(), New Exception()) + {method}(value:= substitute.FooBar(), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], New Exception()) {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) + {method}(value:= [|substituteFooBarBar.Bar|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], New Exception()) + {method}(value:= [|substituteFooBarBar.FooBar()|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -874,10 +884,16 @@ End Namespace var diagnosticMessages = new[] { + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -926,15 +942,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo(Of Integer))() {method}(substitute(1), New Exception()) + {method}(value:= substitute(1), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute(1)) {method}(substitute.Bar, New Exception()) + {method}(value:= substitute.Bar, ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.Bar) {method}(substitute.FooBar(), New Exception()) + {method}(value:= substitute.FooBar(), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar(Of Integer))() {method}([|substituteFooBarBar(1)|], New Exception()) {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) + {method}(value:= [|substituteFooBarBar.Bar|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], New Exception()) + {method}(value:= [|substituteFooBarBar.FooBar()|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -945,9 +971,15 @@ End Namespace var diagnosticMessages = new[] { "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -999,15 +1031,25 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute(1), New Exception()) + {method}(value:= substitute(1), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute(1)) {method}(substitute.Bar, New Exception()) + {method}(value:= substitute.Bar, ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.Bar) {method}(substitute.FooBar(), New Exception()) + {method}(value:= substitute.FooBar(), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.FooBar()) Dim substituteFooBarBar = NSubstitute.Substitute.[For](Of FooBarBar)() {method}([|substituteFooBarBar(1)|], New Exception()) {method}(value:= [|substituteFooBarBar(1)|], ex:= New Exception()) {method}(ex:= New Exception(), value:= [|substituteFooBarBar(1)|]) {method}([|substituteFooBarBar.Bar|], New Exception()) + {method}(value:= [|substituteFooBarBar.Bar|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.Bar|]) {method}([|substituteFooBarBar.FooBar()|], New Exception()) + {method}(value:= [|substituteFooBarBar.FooBar()|], ex:= New Exception()) + {method}(ex:= New Exception(), value:= [|substituteFooBarBar.FooBar()|]) End Sub End Class End Namespace @@ -1018,9 +1060,15 @@ End Namespace var diagnosticMessages = new[] { "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", "Member FooBar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(NonVirtualSetupSpecificationDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 734d3539..e345e1af 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq.Extensions; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -26,6 +27,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]) + {method}(value:= substitute.Bar(), returnThis:= [|ReturnThis()|]) + {method}(returnThis:= [|ReturnThis()|], value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -46,7 +49,9 @@ End Namespace var diagnosticMessages = new[] { $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", - $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn())." + $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn()).", + $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls Returns. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -73,6 +78,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]) + {method}(value:= substitute.Bar(), returnThis:= [|ReturnThis()|]) + {method}(returnThis:= [|ReturnThis()|], value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -93,7 +100,9 @@ End Namespace var diagnosticMessages = new[] { $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", - $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn())." + $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn()).", + $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls ReturnsForAnyArgs. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -119,6 +128,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]) + {method}(value:= substitute.Bar(), returnThis:= [|ReturnThis()|]) + {method}(returnThis:= [|ReturnThis()|], value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -138,7 +149,9 @@ End Namespace var diagnosticMessages = new[] { $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", - $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn())." + $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn()).", + $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls Do. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -164,6 +177,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]) + {method}(value:= substitute.Bar(), returnThis:= [|ReturnThis()|]) + {method}(returnThis:= [|ReturnThis()|], value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -195,6 +210,8 @@ End Namespace { $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) OtherReturn()).", + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(Function(x) NestedReturnThis())." }; @@ -221,6 +238,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), Function(x) ReturnThis()) + {method}(value:= substitute.Bar(), returnThis:= Function(x) ReturnThis()) + {method}(returnThis:= Function(x) ReturnThis(), value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -268,6 +287,8 @@ Public Sub Test() {localVariable} Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), barr) + {method}(value:= substitute.Bar(), returnThis:= barr) + {method}(returnThis:= barr, value:= substitute.Bar()) End Sub Public Function Bar() As IBar @@ -300,6 +321,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), {rootCall}) + {method}(value:= substitute.Bar(), returnThis:= {rootCall}) + {method}(returnThis:= {rootCall}, value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -350,6 +373,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), {rootCall}) + {method}(value:= substitute.Bar(), returnThis:= {rootCall}) + {method}(returnThis:= {rootCall}, value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -395,6 +420,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), {firstReturn}, {secondReturn}) + {method}(value:= substitute.Bar(), returnThis:= {firstReturn}) + {method}(returnThis:= {firstReturn}, value:= substitute.Bar()) End Sub Private Function ReturnThis() As Integer @@ -436,6 +463,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|FooBar.ReturnThis()|]) + {method}(value:= substitute.Bar(), returnThis:= [|FooBar.ReturnThis()|]) + {method}(returnThis:= [|FooBar.ReturnThis()|], value:= substitute.Bar()) End Sub End Class End Namespace @@ -479,6 +508,8 @@ Public Class FooTests Public Async Function Test() As Task Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), [|Await ReturnThis()|]) + {method}(value:= substitute.Bar(), returnThis:= [|Await ReturnThis()|]) + {method}(returnThis:= [|Await ReturnThis()|], value:= substitute.Bar()) End Function Private Async Function ReturnThis() As Task(Of Integer) @@ -584,6 +615,8 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute.FooBar(), GetType([{type}])) + {method}(value:= substitute.FooBar(), returnThis:= GetType([{type}])) + {method}(returnThis:= GetType([{type}]), value:= substitute.FooBar()) End Sub End Class End Namespace"; @@ -611,6 +644,8 @@ Public Sub Test() For Each fooBar In New FooBar(-1) {{}} {method}(substitute.Bar(), fooBar.Value) + {method}(value:= substitute.Bar(), returnThis:= fooBar.Value) + {method}(returnThis:= fooBar.Value, value:= substitute.Bar()) Next End Sub End Class @@ -636,10 +671,23 @@ Public Sub Test() For Each value In Enumerable.Empty(Of Integer)() {method}(firstEnumerator.Current, value + 1) + {method}(value:= firstEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= firstEnumerator.Current) + {method}(firstEnumerator.Current, value + 1) + {method}(value:= firstEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= firstEnumerator.Current) {method}(firstEnumerator.Current, value + 1) + {method}(value:= firstEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= firstEnumerator.Current) {method}(secondEnumerator.Current, value + 1) + {method}(value:= secondEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= secondEnumerator.Current) {method}(thirdEnumerator.Current, value + 1) + {method}(value:= thirdEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= thirdEnumerator.Current) {method}(fourthEnumerator.Current, value + 1) + {method}(value:= fourthEnumerator.Current, returnThis:= value + 1) + {method}(returnThis:= value + 1, value:= fourthEnumerator.Current) Next End Sub End Class @@ -665,6 +713,8 @@ Public Sub Test() firstSubstitute.Id.Returns(45) Dim secondSubstitute = Substitute.[For](Of IFoo)() {method}(secondSubstitute.Id, [|firstSubstitute.Id|]) + {method}(value:= secondSubstitute.Id, returnThis:= [|firstSubstitute.Id|]) + {method}(returnThis:= [|firstSubstitute.Id|], value:= secondSubstitute.Id) End Sub End Class End Namespace"; @@ -693,6 +743,8 @@ End Interface Public Sub Test() Dim secondSubstitute = Substitute.[For](Of IFoo)() {method}(secondSubstitute.Id, [|firstSubstitute.Id|]) + {method}(value:= secondSubstitute.Id, returnThis:= [|firstSubstitute.Id|]) + {method}(returnThis:= [|firstSubstitute.Id|], value:= secondSubstitute.Id) End Sub End Class End Namespace @@ -721,7 +773,11 @@ Public Sub Test() fourthSubstitute.Id.Returns(45) Dim value = fourthSubstitute.Id {method}(secondSubstitute.Id, firstSubstitute.Id) + {method}(value:= secondSubstitute.Id, returnThis: =firstSubstitute.Id) + {method}(returnThis: =firstSubstitute.Id, value:= secondSubstitute.Id) {method}(secondSubstitute.Id, value) + {method}(value:= secondSubstitute.Id, returnThis:= value) + {method}(returnThis:= value, value:= secondSubstitute.Id) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index ab2334e5..9d6cb281 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -1,26 +1,42 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared.Extensibility; -namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.ReceivedInReceivedInOrderAnalyzerTests; - -[CombinatoryData( - "ReceivedExtensions.Received(substitute, Quantity.None())", - "ReceivedExtensions.Received(Of IFoo)(substitute, Quantity.None())", - "SubstituteExtensions.Received(substitute)", - "SubstituteExtensions.Received(Of IFoo)(substitute)", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "ReceivedExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute, Quantity.None())", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", - "SubstituteExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute)", - "SubstituteExtensions.DidNotReceive(substitute)", - "SubstituteExtensions.DidNotReceive(Of IFoo)(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of IFoo)(substitute)")] -public class ReceivedAsOrdinaryMethodTests : ReceivedInReceivedInOrderDiagnosticVerifier +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.ReceivedInReceivedInOrderAnalyzerTests { - public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForMethod(string method) + [CombinatoryData( + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "ReceivedExtensions.Received(Of IFoo)(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of IFoo)(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(Of IFoo)(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute:= substitute)", + "SubstituteExtensions.Received(Of IFoo)(substitute)", + "SubstituteExtensions.Received(Of IFoo)(substitute:= substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "ReceivedExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of IFoo)(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of IFoo)(substitute:= substitute)", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute)", + "SubstituteExtensions.DidNotReceive(Of IFoo)(substitute)", + "SubstituteExtensions.DidNotReceive(Of IFoo)(substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of IFoo)(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of IFoo)(substitute:= substitute)")] + public class ReceivedAsOrdinaryMethodTests : ReceivedInReceivedInOrderDiagnosticVerifier { - var source = $@"Imports NSubstitute + public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForMethod(string method) + { + var source = $@"Imports NSubstitute Imports NSubstitute.ReceivedExtensions Namespace MyNamespace @@ -39,12 +55,12 @@ End Class End Namespace "; - await VerifyDiagnostic(source, method); - } + await VerifyDiagnostic(source, method); + } - public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForProperty(string method) - { - var source = $@"Imports NSubstitute + public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForProperty(string method) + { + var source = $@"Imports NSubstitute Imports NSubstitute.ReceivedExtensions Namespace MyNamespace @@ -63,12 +79,12 @@ End Class End Namespace "; - await VerifyDiagnostic(source, method); - } + await VerifyDiagnostic(source, method); + } - public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForIndexer(string method) - { - var source = $@"Imports NSubstitute + public override async Task ReportsDiagnostic_WhenUsingReceivedLikeMethodInReceivedInOrderBlock_ForIndexer(string method) + { + var source = $@"Imports NSubstitute Imports NSubstitute.ReceivedExtensions Namespace MyNamespace @@ -87,12 +103,12 @@ End Class End Namespace "; - await VerifyDiagnostic(source, method); - } + await VerifyDiagnostic(source, method); + } - public override async Task ReportsNoDiagnostic_WhenUsingReceivedLikeMethodOutsideOfReceivedInOrderBlock(string method) - { - var source = $@"Imports NSubstitute + public override async Task ReportsNoDiagnostic_WhenUsingReceivedLikeMethodOutsideOfReceivedInOrderBlock(string method) + { + var source = $@"Imports NSubstitute Imports NSubstitute.ReceivedExtensions Namespace MyNamespace @@ -118,25 +134,25 @@ End Class End Namespace "; - await VerifyNoDiagnostic(source); - } - - [CombinatoryData( - "ReceivedExtensions.Received(substitute, Quantity.None())", - "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", - "SubstituteExtensions.Received(substitute, 1, 1)", - "SubstituteExtensions.Received(Of Foo)(substitute, 1, 1)", - "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", - "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", - "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceive(Of Foo)(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)")] - public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) - { - var source = $@"Imports System + await VerifyNoDiagnostic(source); + } + + [CombinatoryData( + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", + "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(Of Foo)(substitute, 1, 1)", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) + { + var source = $@"Imports System Imports System.Runtime.CompilerServices Namespace NSubstitute @@ -204,25 +220,29 @@ End Sub End Class End Namespace "; - await VerifyNoDiagnostic(source); - } - - private static string GetPlainMethodName(string methodName) - { - var plainMethodName = methodName.Replace("(Of IFoo)", string.Empty) - .Replace("(substitute, Quantity.None())", string.Empty) - .Replace("(substitute)", string.Empty); - - var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) - .Replace("ReceivedExtensions.", string.Empty); - - return planMethodNameWithoutNamespace; - } - - private async Task VerifyDiagnostic(string source, string methodName) - { - var plainMethodName = GetPlainMethodName(methodName); - - await VerifyDiagnostic(source, Descriptor, $"{plainMethodName} method used in Received.InOrder block."); + await VerifyNoDiagnostic(source); + } + + private static string GetPlainMethodName(string methodName) + { + var plainMethodName = methodName.Replace("(Of IFoo)", string.Empty) + .Replace("(substitute, Quantity.None())", string.Empty) + .Replace("(substitute:= substitute, requiredQuantity:= Quantity.None())", string.Empty) + .Replace("(requiredQuantity:= Quantity.None(), substitute:= substitute)", string.Empty) + .Replace("(substitute:= substitute)", string.Empty) + .Replace("(substitute)", string.Empty); + + var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) + .Replace("ReceivedExtensions.", string.Empty); + + return planMethodNameWithoutNamespace; + } + + private async Task VerifyDiagnostic(string source, string methodName) + { + var plainMethodName = GetPlainMethodName(methodName); + + await VerifyDiagnostic(source, Descriptor, $"{plainMethodName} method used in Received.InOrder block."); + } } -} \ No newline at end of file +} diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs index 91d427b6..cbf9c5fe 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs @@ -36,6 +36,7 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of IFoo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of IFoo)(New Integer() { 1 })|] End Sub End Class End Namespace"; @@ -73,6 +74,7 @@ Namespace MyNamespace Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of Func(Of Integer))(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of Func(Of Integer))(New Integer() { 1 })|] End Sub End Class End Namespace @@ -183,6 +185,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of IFoo, Bar)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of IFoo, Bar)(New Integer() { 1 })|] End Sub End Class End Namespace @@ -307,6 +310,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of Foo)(1, 2, 3)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of Foo)(New Integer() { 1, 2, 3 })|] End Sub End Class End Namespace @@ -327,6 +331,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of Foo)(New Integer() { 1 })|] End Sub End Class End Namespace @@ -347,6 +352,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of Foo)(New Integer() { 1 })|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs index e6d07612..d5d50702 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.SubstituteAnalyzerTests; @@ -17,6 +19,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -37,6 +41,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo)}, New Object() {}) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= New Object() {}) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= New Object() {}, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -57,11 +63,23 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(IFoo)}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo)})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForInterfaceDescriptor, "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.[For]({GetType(IFoo)},Nothing) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.[For]({GetType(IFoo)},Nothing) instead.", + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)},constructorArguments:= Nothing) instead.", + "Can not provide constructor arguments when substituting for an interface. Use NSubstitute.Substitute.[For](constructorArguments:= Nothing,typesToProxy:= {GetType(IFoo)}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForInterfaceDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -77,6 +95,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Func(Of Integer))}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Func(Of Integer))}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Func(Of Integer))}) End Sub End Class End Namespace @@ -94,11 +114,23 @@ Namespace MyNamespace Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Func(Of Integer))}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Func(Of Integer))}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Func(Of Integer))})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForDelegateDescriptor, "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.[For]({GetType(Func(Of Integer))},Nothing) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.[For]({GetType(Func(Of Integer))},Nothing) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.[For](typesToProxy:= {GetType(Func(Of Integer))},constructorArguments:= Nothing) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use NSubstitute.Substitute.[For](constructorArguments:= Nothing,typesToProxy:= {GetType(Func(Of Integer))}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForDelegateDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Theory] @@ -120,6 +152,8 @@ Public Class FooTests Public Sub Test() Dim bar = New Bar() Dim substitute = NSubstitute.Substitute.[For]({proxyExpression}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {proxyExpression}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {proxyExpression}) End Sub End Class End Namespace @@ -143,6 +177,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo), GetType(Bar)}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo), GetType(Bar)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo), GetType(Bar)})|] End Sub End Class End Namespace @@ -162,6 +198,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo), GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo), GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo), GetType(Foo)}) End Sub End Class End Namespace @@ -185,6 +223,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo), GetType(IBar)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo), GetType(IBar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo), GetType(IBar)}) End Sub End Class End Namespace @@ -208,6 +248,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo), GetType(Bar)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo), GetType(Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo), GetType(Bar)}) End Sub End Class End Namespace @@ -231,6 +273,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(IFoo), GetType(Bar)}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo), GetType(Bar)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo), GetType(Bar)})|] End Sub End Class End Namespace @@ -251,6 +295,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -271,6 +317,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -291,6 +339,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -313,6 +363,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -335,6 +387,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -355,6 +409,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, New Object() {1, 2, 3})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -375,6 +431,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -395,6 +453,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -413,6 +473,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -433,6 +495,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({{GetType(Foo)}}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {{GetType(Foo)}}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {{GetType(Foo)}}) End Sub End Class End Namespace @@ -453,6 +517,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({{GetType(Foo)}}, Nothing)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {{GetType(Foo)}}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {{GetType(Foo)}})|] End Sub End Class End Namespace @@ -532,7 +598,11 @@ public override async Task ReportsNoDiagnostic_WhenUsedWithGenericArgument() Namespace MyNamespace Public Class FooTests Public Function Foo(Of T As Class)() As T - Return CType(Substitute.[For]({GetType(T)}, Nothing), T) + Dim substitute = CType(NSubstitute.Substitute.[For]({GetType(T)}, Nothing), T) + Dim otherSubstitute = CType(NSubstitute.Substitute.[For](typesToProxy:= {GetType(T)}, constructorArguments:= Nothing), T) + Dim yetAnotherSubstitute = CType(NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(T)}), T) + + Return substitute End Function End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs index aa03f21b..5c9a84d1 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs @@ -161,6 +161,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(1, 2, 3)|] + Dim otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(New Integer() { 1, 2, 3 })|] End Sub End Class End Namespace @@ -181,6 +182,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(New Object() { 1 })|] End Sub End Class End Namespace @@ -201,6 +203,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(Of Foo)(New Object() { 1 })|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs index cc1e1118..1c9ebcbd 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.SubstituteAnalyzerTests; @@ -17,6 +19,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -38,11 +42,23 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo)})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForInterfaceDescriptor, "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)},Nothing) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)},Nothing) instead.", + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)},constructorArguments:= Nothing) instead.", + "Can not provide constructor arguments when substituting for an interface. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing,typesToProxy:= {GetType(IFoo)}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForInterfaceDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -58,6 +74,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Func(Of Integer))}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Func(Of Integer))}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Func(Of Integer))}) End Sub End Class End Namespace @@ -78,11 +96,23 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Func(Of Integer))}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Func(Of Integer))}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Func(Of Integer))})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, SubstituteConstructorArgumentsForDelegateDescriptor, "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create({GetType(Func(Of Integer))},Nothing) instead."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create({GetType(Func(Of Integer))},Nothing) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Func(Of Integer))},constructorArguments:= Nothing) instead.", + "Can not provide constructor arguments when substituting for a delegate. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing,typesToProxy:= {GetType(Func(Of Integer))}) instead." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(SubstituteConstructorArgumentsForDelegateDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -100,6 +130,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo), GetType(Bar)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo), GetType(Bar)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo), GetType(Bar)})|] End Sub End Class End Namespace @@ -119,6 +151,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo), GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo), GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo), GetType(Foo)}) End Sub End Class End Namespace @@ -142,6 +176,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo), GetType(IBar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo), GetType(IBar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo), GetType(IBar)}) End Sub End Class End Namespace @@ -166,6 +202,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo), GetType(Bar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo), GetType(Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo), GetType(Bar)}) End Sub End Class End Namespace @@ -189,6 +227,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo), GetType(Bar)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo), GetType(Bar)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(IFoo), GetType(Bar)})|] End Sub End Class End Namespace @@ -210,6 +250,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -230,6 +272,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -250,6 +294,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -272,6 +318,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -294,6 +342,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -315,6 +365,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1, 2, 3})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -336,6 +388,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -358,6 +412,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -377,6 +433,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace @@ -397,6 +455,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({{GetType(Foo)}}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {{GetType(Foo)}}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {{GetType(Foo)}}) End Sub End Class End Namespace @@ -417,6 +477,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({{GetType(Foo)}}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {{GetType(Foo)}}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {{GetType(Foo)}})|] End Sub End Class End Namespace"; @@ -499,7 +561,10 @@ Imports NSubstitute.Core Namespace MyNamespace Public Class FooTests Public Function Foo(Of T As Class)() As T - Return CType(SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(T)}, Nothing), T) + Dim substitute = CType(SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(T)}, Nothing), T) + Dim otherSubstitute = CType(SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= New Type() {GetType(T)}, constructorArguments:= Nothing), T) + Dim yetAnotherSubstitute = CType(SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(T)}), T) + Return substitute End Function End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs index a5ad3774..26089d06 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -1,4 +1,6 @@ +using System.Linq; using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensions; using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.SubstituteAnalyzerTests; @@ -18,11 +20,23 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(IFoo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(IFoo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(IFoo)})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, PartialSubstituteForUnsupportedTypeDescriptor, "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(IFoo)}, Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(IFoo)}, Nothing) here."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(IFoo)}, Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(IFoo)}, Nothing) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= New Type() {GetType(IFoo)}, constructorArguments:= Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(IFoo)}, constructorArguments:= Nothing) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(IFoo)}) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(IFoo)}) here." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(PartialSubstituteForUnsupportedTypeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -38,11 +52,23 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Func(Of Integer))}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Func(Of Integer))}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Func(Of Integer))})|] End Sub End Class End Namespace "; - await VerifyDiagnostic(source, PartialSubstituteForUnsupportedTypeDescriptor, "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(Func(Of Integer))}, Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Func(Of Integer))}, Nothing) here."); + var textParserResult = TextParser.GetSpans(source); + + var diagnosticMessages = new[] + { + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(New Type() {GetType(Func(Of Integer))}, Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Func(Of Integer))}, Nothing) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= New Type() {GetType(Func(Of Integer))}, constructorArguments:= Nothing) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Func(Of Integer))}, constructorArguments:= Nothing) here.", + "Can only substitute for parts of classes, not interfaces or delegates. Use SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Func(Of Integer))}) instead of SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Func(Of Integer))}) here." + }; + + var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(PartialSubstituteForUnsupportedTypeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); + await VerifyDiagnostic(textParserResult.Text, diagnostics); } [Fact] @@ -60,6 +86,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -81,6 +109,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -102,6 +132,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -125,6 +157,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)}) End Sub End Class End Namespace @@ -148,6 +182,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing) End Sub End Class End Namespace @@ -170,6 +205,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, New Object() {1, 2, 3})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -192,6 +229,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1}, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -215,6 +254,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1}, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -235,6 +276,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)})|] End Sub End Class End Namespace @@ -256,6 +299,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {{GetType(Foo)}}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {{GetType(Foo)}}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {{GetType(Foo)}}) End Sub End Class End Namespace @@ -277,6 +322,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {{GetType(Foo)}}, Nothing)|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {{GetType(Foo)}}, constructorArguments:= Nothing)|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {{GetType(Foo)}})|] End Sub End Class End Namespace From 464e318b9ee12e2e793df05b00c883c658705e0c Mon Sep 17 00:00:00 2001 From: tpodolak Date: Wed, 31 Aug 2022 19:14:35 +0200 Subject: [PATCH 23/35] GH-153 - simplifying ConstructorArgumentsForInterfaceCodeFixProvider with operations API --- ...torArgumentsForInterfaceCodeFixProvider.cs | 28 +++++++---- ...torArgumentsForInterfaceCodeFixProvider.cs | 48 ++++++++++++------- ...torArgumentsForInterfaceCodeFixProvider.cs | 31 ++++++++---- ...gumentsForInterfaceCodeFixProviderTests.cs | 8 ++-- 4 files changed, 78 insertions(+), 37 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs index 3f117a64..46c4d3f6 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -3,24 +3,36 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.CodeFixProviders; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider +internal sealed class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider { - protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithEmptyArgumentList(InvocationExpressionSyntax invocationExpressionSyntax) + protected override SyntaxNode GetInvocationExpressionSyntaxWithEmptyArgumentList(IInvocationOperation invocationOperation) { - return invocationExpressionSyntax.WithArgumentList(ArgumentList()); + var invocationExpression = (InvocationExpressionSyntax)invocationOperation.Syntax; + + return invocationExpression.WithArgumentList(ArgumentList()); } - protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithNullConstructorArgument(InvocationExpressionSyntax invocationExpressionSyntax) + protected override SyntaxNode GetInvocationExpressionSyntaxWithNullConstructorArgument(IInvocationOperation invocationOperation) { - var nullSyntax = Argument(LiteralExpression(SyntaxKind.NullLiteralExpression)); - var secondArgument = invocationExpressionSyntax.ArgumentList.Arguments.Skip(1).First(); - var argumentListSyntax = invocationExpressionSyntax.ArgumentList.ReplaceNode(secondArgument, nullSyntax); - return invocationExpressionSyntax.WithArgumentList(argumentListSyntax); + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; + var arguments = invocationOperation.Arguments.Select(argumentOperation => + { + var argumentSyntax = (ArgumentSyntax)argumentOperation.Syntax; + if (argumentOperation.Parameter.Ordinal > 0) + { + argumentSyntax = argumentSyntax.WithExpression(LiteralExpression(SyntaxKind.NullLiteralExpression)); + } + + return argumentSyntax; + }); + + return invocationExpressionSyntax.WithArgumentList(ArgumentList(SeparatedList(arguments))); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs index 4d073042..ae4ad0c1 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -5,46 +5,60 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Operations; using Document = Microsoft.CodeAnalysis.Document; namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractConstructorArgumentsForInterfaceCodeFixProvider - : CodeFixProvider - where TInvocationExpressionSyntax : SyntaxNode +internal abstract class AbstractConstructorArgumentsForInterfaceCodeFixProvider : CodeFixProvider { public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); public override Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => diag.Descriptor.Id == DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); - if (diagnostic != null) + var diagnostic = context.Diagnostics.FirstOrDefault(diag => + diag.Descriptor.Id == DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); + if (diagnostic == null) { - var codeAction = CodeAction.Create("Remove constructor arguments", ct => CreateChangedDocument(ct, context, diagnostic), nameof(AbstractConstructorArgumentsForInterfaceCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + return Task.CompletedTask; } + var codeAction = CodeAction.Create( + "Remove constructor arguments", + ct => CreateChangedDocument(ct, context, diagnostic), + nameof(AbstractConstructorArgumentsForInterfaceCodeFixProvider)); + context.RegisterCodeFix(codeAction, diagnostic); + return Task.CompletedTask; } - protected abstract TInvocationExpressionSyntax GetInvocationExpressionSyntaxWithEmptyArgumentList(TInvocationExpressionSyntax invocationExpressionSyntax); + protected abstract SyntaxNode GetInvocationExpressionSyntaxWithEmptyArgumentList(IInvocationOperation invocationOperation); - protected abstract TInvocationExpressionSyntax GetInvocationExpressionSyntaxWithNullConstructorArgument(TInvocationExpressionSyntax invocationExpressionSyntax); + protected abstract SyntaxNode GetInvocationExpressionSyntaxWithNullConstructorArgument(IInvocationOperation invocationOperation); private async Task CreateChangedDocument(CancellationToken cancellationToken, CodeFixContext context, Diagnostic diagnostic) { + var documentEditor = await DocumentEditor.CreateAsync(context.Document, cancellationToken); + var root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var invocation = (TInvocationExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var invocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken); - var updatedInvocation = semanticModel.GetSymbolInfo(invocation).Symbol is IMethodSymbol methodSymbol && - methodSymbol.IsGenericMethod - ? GetInvocationExpressionSyntaxWithEmptyArgumentList(invocation) - : GetInvocationExpressionSyntaxWithNullConstructorArgument(invocation); + if (semanticModel.GetOperation(invocation) is not IInvocationOperation invocationOperation) + { + return context.Document; + } + + var updatedInvocation = invocationOperation.TargetMethod.IsGenericMethod + ? GetInvocationExpressionSyntaxWithEmptyArgumentList(invocationOperation) + : GetInvocationExpressionSyntaxWithNullConstructorArgument(invocationOperation); + + documentEditor.ReplaceNode(invocation, updatedInvocation); - var replacedRoot = root.ReplaceNode(invocation, updatedInvocation); - return context.Document.WithSyntaxRoot(replacedRoot); + return documentEditor.GetChangedDocument(); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs index bb93d6d4..915c80ae 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; @@ -9,18 +10,32 @@ namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider +internal sealed class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider { - protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithEmptyArgumentList(InvocationExpressionSyntax invocationExpressionSyntax) + protected override SyntaxNode GetInvocationExpressionSyntaxWithEmptyArgumentList(IInvocationOperation invocationOperation) { - return invocationExpressionSyntax.WithArgumentList(ArgumentList()); + var invocationExpression = (InvocationExpressionSyntax)invocationOperation.Syntax; + + return invocationExpression.WithArgumentList(ArgumentList()); } - protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithNullConstructorArgument(InvocationExpressionSyntax invocationExpressionSyntax) + protected override SyntaxNode GetInvocationExpressionSyntaxWithNullConstructorArgument(IInvocationOperation invocationOperation) { - var nullSyntax = SimpleArgument(LiteralExpression(SyntaxKind.NothingLiteralExpression, Token(SyntaxKind.NothingKeyword))); - var seconArgument = invocationExpressionSyntax.ArgumentList.Arguments.Skip(1).First(); - var argumentListSyntax = invocationExpressionSyntax.ArgumentList.ReplaceNode(seconArgument, nullSyntax); - return invocationExpressionSyntax.WithArgumentList(argumentListSyntax); + var invocationExpressionSyntax = (InvocationExpressionSyntax)invocationOperation.Syntax; + var arguments = invocationOperation.Arguments + .OrderBy(x => x.Syntax.GetLocation().GetLineSpan().StartLinePosition.Character) + .Select(argumentOperation => + { + var argumentSyntax = (SimpleArgumentSyntax)argumentOperation.Syntax; + if (argumentOperation.Parameter.Ordinal > 0) + { + argumentSyntax = argumentSyntax.WithExpression( + LiteralExpression(SyntaxKind.NothingLiteralExpression, Token(SyntaxKind.NothingKeyword))); + } + + return argumentSyntax; + }); + + return invocationExpressionSyntax.WithArgumentList(ArgumentList(SeparatedList(arguments))); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs index f04f2170..236a0a48 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs @@ -76,8 +76,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(IFoo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(IFoo)}, constructorArguments:=Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:=Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace @@ -114,8 +114,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(IFoo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(IFoo)}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(IFoo)}, constructorArguments:=Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:=Nothing, typesToProxy:= {GetType(IFoo)}) End Sub End Class End Namespace From 2ae2709e67cabc09d56a6fbeb5e21ab494e1e5d7 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 11 Oct 2020 18:33:56 +0200 Subject: [PATCH 24/35] GH-153 - simplifing PartialSubstituteUsedForUnsupportedTypeCodeFixProvider --- ...teUsedForUnsupportedTypeCodeFixProvider.cs | 17 ++-- ...teUsedForUnsupportedTypeCodeFixProvider.cs | 85 +++++++++---------- ...stituteForInternalMemberCodeFixProvider.cs | 5 +- ...teUsedForUnsupportedTypeCodeFixProvider.cs | 17 ++-- 4 files changed, 59 insertions(+), 65 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index 91e86ae4..b3dc859a 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -2,22 +2,21 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; using NSubstitute.Analyzers.Shared.CodeFixProviders; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider +internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider { - protected override TInnerNameSyntax GetNameSyntax(InvocationExpressionSyntax methodInvocationNode) + protected override SyntaxNode UpdateInvocationExpression(IInvocationOperation invocationOperation, string identifierName) { - var memberAccess = (MemberAccessExpressionSyntax)methodInvocationNode.Expression; - return (TInnerNameSyntax)memberAccess.Name; - } - - protected override TInnerNameSyntax GetUpdatedNameSyntax(TInnerNameSyntax nameSyntax, string identifierName) - { - return (TInnerNameSyntax)nameSyntax.WithIdentifier(IdentifierName(identifierName).Identifier); + var invocationExpression = (InvocationExpressionSyntax)invocationOperation.Syntax; + var memberAccessExpression = (MemberAccessExpressionSyntax)invocationExpression.Expression; + return invocationExpression.WithExpression( + memberAccessExpression.WithName( + memberAccessExpression.Name.WithIdentifier(Identifier(identifierName)))); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index a49db4e4..66b50d54 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -1,72 +1,69 @@ using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider - : CodeFixProvider - where TInvocationExpression : SyntaxNode - where TGenericNameSyntax : TNameSyntax - where TIdentifierNameSyntax : TNameSyntax - where TNameSyntax : SyntaxNode +internal abstract class AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider : CodeFixProvider { public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => diag.Descriptor.Id == DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); - if (diagnostic != null) + var diagnostic = context.Diagnostics.FirstOrDefault(diag => + diag.Descriptor.Id == DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); + if (diagnostic == null) { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var invocationExpression = (TInvocationExpression)root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); - var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); + return; + } - if (semanticModel.GetSymbolInfo(invocationExpression).Symbol is not IMethodSymbol methodSymbol) - { - return; - } + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var syntaxNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - var title = methodSymbol.Name == MetadataNames.SubstituteFactoryCreatePartial ? "Use SubstituteFactory.Create" : "Use Substitute.For"; - var codeAction = CodeAction.Create( - title, - ct => CreateChangedDocument(context, root, methodSymbol, invocationExpression), - nameof(AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + if (semanticModel.GetOperation(syntaxNode) is not IInvocationOperation invocationOperation) + { + return; } - } - protected abstract TInnerNameSyntax GetNameSyntax(TInvocationExpression methodInvocationNode) where TInnerNameSyntax : TNameSyntax; + var title = invocationOperation.TargetMethod.Name == MetadataNames.SubstituteFactoryCreatePartial + ? "Use SubstituteFactory.Create" + : "Use Substitute.For"; - protected abstract TInnerNameSyntax GetUpdatedNameSyntax(TInnerNameSyntax nameSyntax, string identifierName) where TInnerNameSyntax : TNameSyntax; + var codeAction = CodeAction.Create( + title, + ct => CreateChangedDocument(context, invocationOperation, ct), + nameof(AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider)); + context.RegisterCodeFix(codeAction, diagnostic); + } - private Task CreateChangedDocument(CodeFixContext context, SyntaxNode root, IMethodSymbol methodSymbol, TInvocationExpression invocationExpression) - { - SyntaxNode nameNode; - SyntaxNode updateNameNode; + protected abstract SyntaxNode UpdateInvocationExpression( + IInvocationOperation invocationOperation, + string identifierName); - if (methodSymbol.IsGenericMethod) - { - var genericNameSyntax = GetNameSyntax(invocationExpression); - nameNode = genericNameSyntax; - updateNameNode = GetUpdatedNameSyntax(genericNameSyntax, MetadataNames.NSubstituteForMethod); - } - else - { - var identifierNameSyntax = GetNameSyntax(invocationExpression); - nameNode = identifierNameSyntax; - updateNameNode = GetUpdatedNameSyntax(identifierNameSyntax, MetadataNames.SubstituteFactoryCreate); - } + private async Task CreateChangedDocument( + CodeFixContext context, + IInvocationOperation invocationOperation, + CancellationToken cancellationToken) + { + var documentEditor = await DocumentEditor.CreateAsync(context.Document, cancellationToken); + var newIdentifierName = invocationOperation.TargetMethod.IsGenericMethod + ? MetadataNames.NSubstituteForMethod + : MetadataNames.SubstituteFactoryCreate; - var forNode = invocationExpression.ReplaceNode(nameNode, updateNameNode); + var updatedInvocationExpression = UpdateInvocationExpression(invocationOperation, newIdentifierName); - var replaceNode = root.ReplaceNode(invocationExpression, forNode); + documentEditor.ReplaceNode(invocationOperation.Syntax, updatedInvocationExpression); - return Task.FromResult(context.Document.WithSyntaxRoot(replaceNode)); + return documentEditor.GetChangedDocument(); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index eab32bd9..ba865025 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -32,8 +32,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var invocationExpression = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - if (invocationExpression is not { } || - semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) + if (semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) { return; } @@ -66,6 +65,6 @@ private SyntaxReference GetDeclaringSyntaxReference(IInvocationOperation invocat private TCompilationUnitSyntax FindCompilationUnitSyntax(SyntaxNode syntaxNode) { - return syntaxNode.Parent.Ancestors().OfType().LastOrDefault(); + return syntaxNode.Ancestors().OfType().LastOrDefault(); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index 5159c2b8..43325d9b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/PartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; @@ -8,16 +9,14 @@ namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider +internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider { - protected override TInnerNameSyntax GetNameSyntax(InvocationExpressionSyntax methodInvocationNode) + protected override SyntaxNode UpdateInvocationExpression(IInvocationOperation invocationOperation, string identifierName) { - var memberAccess = (MemberAccessExpressionSyntax)methodInvocationNode.Expression; - return memberAccess.Name as TInnerNameSyntax; - } - - protected override TInnerNameSyntax GetUpdatedNameSyntax(TInnerNameSyntax nameSyntax, string identifierName) - { - return (TInnerNameSyntax)nameSyntax.WithIdentifier(IdentifierName(identifierName).Identifier); + var invocationExpression = (InvocationExpressionSyntax)invocationOperation.Syntax; + var memberAccessExpression = (MemberAccessExpressionSyntax)invocationExpression.Expression; + return invocationExpression.WithExpression( + memberAccessExpression.WithName( + memberAccessExpression.Name.WithIdentifier(Identifier(identifierName)))); } } \ No newline at end of file From 8e7e8328f2fc5b2e3fdc3b74a190f59749bb3a04 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Thu, 1 Sep 2022 22:12:21 +0200 Subject: [PATCH 25/35] GH-153 - removing duplicate code --- .../NonSubstitutableMemberAnalysis.cs | 15 +-------------- .../DiagnosticAnalyzers/SubstitutionNodeFinder.cs | 14 +------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs index 5092d2bd..01495f6c 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/NonSubstitutableMemberAnalysis.cs @@ -14,7 +14,7 @@ internal class NonSubstitutableMemberAnalysis : INonSubstitutableMemberAnalysis public NonSubstitutableMemberAnalysisResult Analyze(IOperation operation) { - var symbol = ExtractSymbol(operation); + var symbol = operation.ExtractSymbol(); return Analyze(operation, symbol); } @@ -85,19 +85,6 @@ private static bool IsVirtual(ISymbol symbol) return isVirtual; } - private static ISymbol ExtractSymbol(IOperation operation) - { - var symbol = operation switch - { - IInvocationOperation invocationOperation => invocationOperation.TargetMethod, - IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, - IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), - IMemberReferenceOperation memberReferenceOperation => memberReferenceOperation.Member, - _ => null - }; - return symbol; - } - private static IOperation ExtractActualOperation(IOperation operation) { return operation switch diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 406903b3..92e5c4bb 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -66,7 +66,7 @@ public IEnumerable FindForWhenExpression(Compilation compilation, II foreach (var operation in whenVisitor.Operations) { - var symbol = ExtractSymbol(operation); + var symbol = operation.ExtractSymbol(); if (symbol != null && ContainsSymbol(typeSymbol, symbol)) { @@ -106,18 +106,6 @@ private static IEnumerable GetBaseTypesAndThis(ITypeSymbol type) } } - private static ISymbol ExtractSymbol(IOperation operation) - { - var symbol = operation switch - { - IInvocationOperation invocationOperation => invocationOperation.TargetMethod, - IPropertyReferenceOperation propertyReferenceOperation => propertyReferenceOperation.Property, - IConversionOperation conversionOperation => ExtractSymbol(conversionOperation.Operand), - _ => null - }; - return symbol; - } - private IOperation FindForAndDoesExpression(IInvocationOperation invocationOperation) { if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationOperation) From c154f46c2a17237e553e0c9ddbd9a84d04821bae Mon Sep 17 00:00:00 2001 From: tpodolak Date: Thu, 1 Sep 2022 00:36:39 +0200 Subject: [PATCH 26/35] GH-153 - ReEntrantFixProvider support for out of order arguments --- .../ReEntrantSetupCodeFixProvider.cs | 82 ++------- .../Extensions/ExpressionSyntaxExtensions.cs | 27 --- .../AbstractReEntrantSetupCodeFixProvider.cs | 165 ++++++++++++------ .../Extensions/IOperationExtensions.cs | 6 +- .../ReEntrantSetupCodeFixProvider.cs | 104 ++--------- .../Extensions/ExpressionSyntaxExtensions.cs | 23 --- .../ReEntrantSetupCodeFixVerifier.cs | 6 - .../ReturnsAsExtensionMethodTests.cs | 12 ++ .../ReturnsAsOrdinaryMethodTests.cs | 21 ++- .../ReEntrantSetupCodeFixVerifier.cs | 4 - .../ReturnsAsExtensionMethodTests.cs | 10 ++ .../ReturnsAsOrdinaryMethodTests.cs | 15 +- 12 files changed, 193 insertions(+), 282 deletions(-) delete mode 100644 src/NSubstitute.Analyzers.CSharp/Extensions/ExpressionSyntaxExtensions.cs delete mode 100644 src/NSubstitute.Analyzers.VisualBasic/Extensions/ExpressionSyntaxExtensions.cs diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs index 45320844..98c9d7c4 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs @@ -1,94 +1,36 @@ -using System; using System.Collections.Generic; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Simplification; -using NSubstitute.Analyzers.CSharp.Extensions; using NSubstitute.Analyzers.Shared.CodeFixProviders; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace NSubstitute.Analyzers.CSharp.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.CSharp)] -internal sealed class ReEntrantSetupCodeFixProvider : AbstractReEntrantSetupCodeFixProvider +internal sealed class ReEntrantSetupCodeFixProvider : AbstractReEntrantSetupCodeFixProvider { - protected override int AwaitExpressionRawKind { get; } = (int)SyntaxKind.AwaitExpression; + protected override string LambdaParameterName => "_"; - protected override ArgumentSyntax CreateUpdatedArgumentSyntaxNode(ArgumentSyntax argumentSyntaxNode) - { - return argumentSyntaxNode.WithExpression(CreateSimpleLambdaExpressionNode(argumentSyntaxNode.Expression)); - } - - protected override IEnumerable GetParameterExpressionsFromArrayArgument(ArgumentSyntax argumentSyntaxNode) - { - return argumentSyntaxNode.Expression.GetParameterExpressionsFromArrayArgument()?.Select(syntax => syntax); - } - - protected override ArgumentSyntax CreateUpdatedParamsArgumentSyntaxNode( - SyntaxGenerator syntaxGenerator, - ITypeSymbol typeSymbol, - ArgumentSyntax argumentSyntaxNode) - { - var expression = argumentSyntaxNode.Expression; - - var resultArrayCreationExpressionSyntax = expression switch - { - ArrayCreationExpressionSyntax arrayCreationExpressionSyntax => CreateArrayCreationExpression( - syntaxGenerator, typeSymbol, arrayCreationExpressionSyntax.Initializer), - ImplicitArrayCreationExpressionSyntax implicitArrayCreationExpressionSyntax => - CreateArrayCreationExpression(syntaxGenerator, typeSymbol, implicitArrayCreationExpressionSyntax.Initializer), - _ => throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)) - }; - - return argumentSyntaxNode.WithExpression(resultArrayCreationExpressionSyntax); - } - - protected override IEnumerable GetArguments(ArgumentListSyntax argumentSyntax) - { - return argumentSyntax.Arguments; - } + protected override ArgumentSyntax UpdateArgumentExpression(ArgumentSyntax argument, SyntaxNode expression) => argument.WithExpression((ExpressionSyntax)expression); - protected override SyntaxNode GetArgumentExpressionSyntax(ArgumentSyntax argumentSyntax) - { - return argumentSyntax.Expression; - } + protected override SyntaxNode GetArgumentExpression(ArgumentSyntax argument) => argument.Expression; - private static SimpleLambdaExpressionSyntax CreateSimpleLambdaExpressionNode(SyntaxNode content) + protected override SyntaxNode CreateArrayCreationExpression(SyntaxNode typeSyntax, IEnumerable elements) { - return SimpleLambdaExpression( - Parameter(Identifier("_").WithTrailingTrivia(Space)), - (CSharpSyntaxNode)content.WithLeadingTrivia(Space)); - } + var initializer = InitializerExpression(SyntaxKind.ArrayInitializerExpression, SeparatedList(elements)); - private static ArrayCreationExpressionSyntax CreateArrayCreationExpression( - SyntaxGenerator syntaxGenerator, - ITypeSymbol typeSymbol, - InitializerExpressionSyntax initializerExpressionSyntax) - { - var arrayType = CreateArrayTypeNode(syntaxGenerator, typeSymbol); - var syntaxes = CreateSimpleLambdaExpressions(initializerExpressionSyntax); + var arrayRankSpecifierSyntaxes = SingletonList(ArrayRankSpecifier(SingletonSeparatedList(OmittedArraySizeExpression()))); - var initializer = InitializerExpression(SyntaxKind.ArrayInitializerExpression, syntaxes); + var arrayType = ArrayType((TypeSyntax)typeSyntax, arrayRankSpecifierSyntaxes) + .WithAdditionalAnnotations(Simplifier.Annotation); return ArrayCreationExpression(arrayType, initializer); } - private static SeparatedSyntaxList CreateSimpleLambdaExpressions(InitializerExpressionSyntax initializerExpressionSyntax) - { - var expressions = initializerExpressionSyntax.Expressions.Select(CreateSimpleLambdaExpressionNode); - return SeparatedList(expressions); - } - - private static ArrayTypeSyntax CreateArrayTypeNode(SyntaxGenerator syntaxGenerator, ITypeSymbol type) - { - var typeSyntax = (TypeSyntax)syntaxGenerator.TypeExpression(type); - - var arrayRankSpecifierSyntaxes = SingletonList(ArrayRankSpecifier(SingletonSeparatedList(OmittedArraySizeExpression()))); - - return ArrayType(typeSyntax, arrayRankSpecifierSyntaxes).WithAdditionalAnnotations(Simplifier.Annotation); - } + protected override IReadOnlyList GetArguments(IInvocationOperation invocationOperation) => + ((InvocationExpressionSyntax)invocationOperation.Syntax).ArgumentList.Arguments; } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Extensions/ExpressionSyntaxExtensions.cs b/src/NSubstitute.Analyzers.CSharp/Extensions/ExpressionSyntaxExtensions.cs deleted file mode 100644 index 1dc537dd..00000000 --- a/src/NSubstitute.Analyzers.CSharp/Extensions/ExpressionSyntaxExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace NSubstitute.Analyzers.CSharp.Extensions; - -internal static class ExpressionSyntaxExtensions -{ - public static IList GetParameterExpressionsFromArrayArgument(this ExpressionSyntax expression) - { - InitializerExpressionSyntax initializer; - switch (expression.Kind()) - { - case SyntaxKind.ArrayCreationExpression: - initializer = ((ArrayCreationExpressionSyntax)expression).Initializer; - break; - case SyntaxKind.ImplicitArrayCreationExpression: - initializer = ((ImplicitArrayCreationExpressionSyntax)expression).Initializer; - break; - default: - return null; - } - - return initializer.Expressions.ToList(); - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs index 5579cb4f..62dbcbbd 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs @@ -13,22 +13,11 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; -internal abstract class AbstractReEntrantSetupCodeFixProvider : CodeFixProvider - where TArgumentListSyntax : SyntaxNode +internal abstract class AbstractReEntrantSetupCodeFixProvider : CodeFixProvider where TArgumentSyntax : SyntaxNode { public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.ReEntrantSubstituteCall); - protected abstract TArgumentSyntax CreateUpdatedArgumentSyntaxNode(TArgumentSyntax argumentSyntaxNode); - - protected abstract TArgumentSyntax CreateUpdatedParamsArgumentSyntaxNode(SyntaxGenerator syntaxGenerator, ITypeSymbol returnedTypeSymbol, TArgumentSyntax argumentSyntaxNode); - - protected abstract SyntaxNode GetArgumentExpressionSyntax(TArgumentSyntax argumentSyntax); - - protected abstract IEnumerable GetParameterExpressionsFromArrayArgument(TArgumentSyntax argumentSyntaxNode); - - protected abstract int AwaitExpressionRawKind { get; } - public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.FirstOrDefault(diag => @@ -39,62 +28,102 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } + var semanticModel = await context.Document.GetSemanticModelAsync(); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken); var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); - var semanticModel = await context.Document.GetSemanticModelAsync(); - var argumentList = GetArgumentListSyntax(node); - var allArguments = GetArguments(argumentList).ToList(); + if (semanticModel.GetOperation(node) is not { } nodeOperation) + { + return; + } + + var invocationOperation = nodeOperation.Ancestors().OfType().FirstOrDefault(); + + if (invocationOperation == null) + { + return; + } + + if (semanticModel.GetSymbolInfo(invocationOperation.Syntax).Symbol is not IMethodSymbol methodSymbol) + { + return; + } - if (IsFixSupported(semanticModel, allArguments) == false) + if (IsFixSupported(invocationOperation) == false) { return; } var codeAction = CodeAction.Create( "Replace with lambda", - ct => CreateChangedDocument(context, argumentList, allArguments, ct), - nameof(AbstractReEntrantSetupCodeFixProvider)); + ct => CreateChangedDocument(context, semanticModel, invocationOperation, methodSymbol, ct), + nameof(AbstractReEntrantSetupCodeFixProvider)); context.RegisterCodeFix(codeAction, diagnostic); } - protected abstract IEnumerable GetArguments(TArgumentListSyntax argumentSyntax); + protected abstract string LambdaParameterName { get; } + + protected abstract IReadOnlyList GetArguments(IInvocationOperation invocationOperation); + + protected abstract TArgumentSyntax UpdateArgumentExpression(TArgumentSyntax argument, SyntaxNode expression); + + protected abstract SyntaxNode GetArgumentExpression(TArgumentSyntax argument); + + // syntaxGenerator.ArrayCreationExpression() generates invalid syntax in current version of Roslyn, so we have to + // generate array expression per language on our own + protected abstract SyntaxNode CreateArrayCreationExpression(SyntaxNode typeSyntax, IEnumerable elements); + + private IEnumerable GetArrayOperationValues(IArgumentOperation argumentOperation) + { + return argumentOperation.Value switch + { + IArrayCreationOperation arrayCreationOperation => arrayCreationOperation.Initializer.ElementValues, + IArrayInitializerOperation arrayInitializerOperation => arrayInitializerOperation.ElementValues, + _ => null + }; + } private async Task CreateChangedDocument( CodeFixContext context, - TArgumentListSyntax argumentListSyntax, - IReadOnlyList argumentSyntaxes, + SemanticModel semanticModel, + IInvocationOperation invocationOperation, + IMethodSymbol methodSymbol, CancellationToken ct) { var documentEditor = await DocumentEditor.CreateAsync(context.Document, ct); - var semanticModel = await context.Document.GetSemanticModelAsync(ct); - var invocationSyntaxNode = argumentListSyntax.Parent; - if (semanticModel.GetSymbolInfo(invocationSyntaxNode).Symbol is not IMethodSymbol methodSymbol) + var syntaxGenerator = SyntaxGenerator.GetGenerator(context.Document); + + // we cant use syntax directly from invocationOperation.Arguments because for params expression + // passed as separated values, operation syntax is not ArgumentSyntax + var arguments = GetArguments(invocationOperation); + foreach (var (argumentSyntax, argumentOperation) in arguments.GroupJoin( + invocationOperation.Arguments, + argument => argument, + operation => operation.Syntax, + (argument, argumentOperation) => (argument, argumentOperation.SingleOrDefault()))) { - return context.Document; - } - - var skip = methodSymbol.MethodKind == MethodKind.Ordinary - ? 1 - : 0; + if (methodSymbol.MethodKind == MethodKind.Ordinary && + argumentOperation is not null && + argumentOperation.Parameter.Ordinal == 0) + { + continue; + } - ITypeSymbol lambdaType = null; - foreach (var argumentSyntax in argumentSyntaxes.Skip(skip)) - { - if (IsArrayParamsArgument(semanticModel, argumentSyntax)) + if (IsArrayParamsArgument(argumentOperation)) { - lambdaType ??= ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); - var updatedParamsArgumentSyntaxNode = CreateUpdatedParamsArgumentSyntaxNode( - SyntaxGenerator.GetGenerator(context.Document), - lambdaType, + var updatedParamsArgumentSyntaxNode = CreateUpdatedParamsArgument( + semanticModel, + methodSymbol, + argumentOperation, + syntaxGenerator, argumentSyntax); documentEditor.ReplaceNode(argumentSyntax, updatedParamsArgumentSyntaxNode); } else { - var updatedArgumentSyntax = CreateUpdatedArgumentSyntaxNode(argumentSyntax); + var updatedArgumentSyntax = CreateUpdatedArgument(syntaxGenerator, argumentSyntax); documentEditor.ReplaceNode(argumentSyntax, updatedArgumentSyntax); } @@ -103,6 +132,31 @@ private async Task CreateChangedDocument( return await Simplifier.ReduceAsync(documentEditor.GetChangedDocument(), cancellationToken: ct); } + private TArgumentSyntax CreateUpdatedParamsArgument( + SemanticModel semanticModel, + IMethodSymbol methodSymbol, + IArgumentOperation argumentOperation, + SyntaxGenerator syntaxGenerator, + TArgumentSyntax argumentSyntax) + { + var lambdaType = ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); + var lambdaTypeSyntax = syntaxGenerator.TypeExpression(lambdaType); + var arrayElements = GetArrayOperationValues(argumentOperation) + .Select(operation => CreateLambdaExpression(syntaxGenerator, operation.Syntax)); + var arrayCreationExpression = + CreateArrayCreationExpression(lambdaTypeSyntax, arrayElements); + + return UpdateArgumentExpression(argumentSyntax, arrayCreationExpression); + } + + private TArgumentSyntax CreateUpdatedArgument(SyntaxGenerator syntaxGenerator, TArgumentSyntax argument) + { + var expression = GetArgumentExpression(argument); + var lambdaExpression = CreateLambdaExpression(syntaxGenerator, expression); + + return UpdateArgumentExpression(argument, lambdaExpression); + } + private static ITypeSymbol ConstructCallInfoLambdaType(IMethodSymbol methodSymbol, Compilation compilation) { var callInfoOverloadMethodSymbol = methodSymbol.ContainingType.GetMembers(methodSymbol.Name) @@ -112,33 +166,28 @@ private static ITypeSymbol ConstructCallInfoLambdaType(IMethodSymbol methodSymbo var typeArgument = methodSymbol.TypeArguments.FirstOrDefault() ?? methodSymbol.ReceiverType; var constructedOverloadSymbol = callInfoOverloadMethodSymbol.Construct(typeArgument); - var lambdaType = constructedOverloadSymbol.Parameters - .First(param => param.Type.IsCallInfoDelegate(compilation)).Type; - return lambdaType; + return constructedOverloadSymbol.Parameters + .First(param => param.Type.IsCallInfoDelegate(compilation)).Type; } - private bool IsFixSupported(SemanticModel semanticModel, IEnumerable arguments) + private bool IsFixSupported(IInvocationOperation invocationOperation) { - return arguments.All(arg => + return invocationOperation.Arguments.All(argumentOperation => { - var expressionSyntax = GetArgumentExpressionSyntax(arg); - var arrayExpressions = GetParameterExpressionsFromArrayArgument(arg); + if (argumentOperation.Value is IAwaitOperation) + { + return false; + } - return expressionSyntax.RawKind != AwaitExpressionRawKind && - (IsArrayParamsArgument(semanticModel, arg) == false || (arrayExpressions != null && arrayExpressions.All(exp => exp.RawKind != AwaitExpressionRawKind))); + var arrayValues = GetArrayOperationValues(argumentOperation); + return IsArrayParamsArgument(argumentOperation) == false || (arrayValues != null && arrayValues.All(exp => exp is not IAwaitOperation)); }); } - private bool IsArrayParamsArgument(SemanticModel semanticModel, TArgumentSyntax argumentSyntax) - { - var operation = semanticModel.GetOperation(argumentSyntax); - return operation is IArgumentOperation argumentOperation && argumentOperation.Parameter.IsParams; - } + private bool IsArrayParamsArgument(IArgumentOperation operation) => + operation != null && operation.Parameter.IsParams; - private static TArgumentListSyntax GetArgumentListSyntax(SyntaxNode diagnosticNode) - { - var argumentListSyntax = diagnosticNode.Ancestors().OfType().FirstOrDefault(); - return argumentListSyntax; - } + private SyntaxNode CreateLambdaExpression(SyntaxGenerator syntaxGenerator, SyntaxNode statement) => + syntaxGenerator.ValueReturningLambdaExpression(LambdaParameterName, statement); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 7329bf64..15bc630d 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -94,13 +94,11 @@ public static ITypeSymbol GetTypeSymbol(this IArgumentOperation argumentOperatio public static ITypeSymbol GetTypeSymbol(this IAssignmentOperation assignmentOperation) { - var conversionTypeSymbol = assignmentOperation.Value switch + return assignmentOperation.Value switch { IConversionOperation conversionOperation => conversionOperation.Operand.Type, - _ => null + _ => assignmentOperation.Value.Type }; - - return conversionTypeSymbol ?? assignmentOperation.Value.Type; } public static IEnumerable Ancestors(this IOperation operation) diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs index ad3495a7..93a1b87b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/ReEntrantSetupCodeFixProvider.cs @@ -1,112 +1,44 @@ -using System; using System.Collections.Generic; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; -using NSubstitute.Analyzers.VisualBasic.Extensions; using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; [ExportCodeFixProvider(LanguageNames.VisualBasic)] -internal sealed class ReEntrantSetupCodeFixProvider : AbstractReEntrantSetupCodeFixProvider +internal sealed class ReEntrantSetupCodeFixProvider : AbstractReEntrantSetupCodeFixProvider { - protected override ArgumentSyntax CreateUpdatedArgumentSyntaxNode(ArgumentSyntax argumentSyntaxNode) - { - var expressionSyntax = argumentSyntaxNode.GetExpression(); - - var lambdaExpression = CreateSingleLineLambdaExpression(expressionSyntax); + protected override string LambdaParameterName => "x"; - return argumentSyntaxNode switch - { - SimpleArgumentSyntax simpleArgumentSyntax => simpleArgumentSyntax.WithExpression(lambdaExpression), - _ => argumentSyntaxNode - }; - } + protected override IReadOnlyList GetArguments(IInvocationOperation invocationOperation) => + ((InvocationExpressionSyntax)invocationOperation.Syntax).ArgumentList.Arguments; - protected override ArgumentSyntax CreateUpdatedParamsArgumentSyntaxNode(SyntaxGenerator syntaxGenerator, ITypeSymbol typeSymbol, ArgumentSyntax argumentSyntaxNode) + protected override ArgumentSyntax UpdateArgumentExpression(ArgumentSyntax argument, SyntaxNode expression) { - if (argumentSyntaxNode is not SimpleArgumentSyntax simpleArgumentSyntax) - { - return argumentSyntaxNode; - } - - var expression = argumentSyntaxNode.GetExpression(); - - var resultArrayCreationExpressionSyntax = expression switch + return argument switch { - ArrayCreationExpressionSyntax arrayCreationExpressionSyntax => CreateArrayCreationExpression( - syntaxGenerator, typeSymbol, arrayCreationExpressionSyntax.Initializer.Initializers), - CollectionInitializerSyntax implicitArrayCreationExpressionSyntax => CreateArrayCreationExpression( - syntaxGenerator, typeSymbol, implicitArrayCreationExpressionSyntax.Initializers), - _ => throw new ArgumentException($"{argumentSyntaxNode.Kind()} is not recognized as array initialization", nameof(argumentSyntaxNode)) + SimpleArgumentSyntax simpleArgumentSyntax => simpleArgumentSyntax.WithExpression((ExpressionSyntax)expression), + _ => argument }; - - return simpleArgumentSyntax.WithExpression(resultArrayCreationExpressionSyntax); - } - - protected override SyntaxNode GetArgumentExpressionSyntax(ArgumentSyntax argumentSyntax) - { - return argumentSyntax.GetExpression(); - } - - protected override IEnumerable GetParameterExpressionsFromArrayArgument(ArgumentSyntax argumentSyntaxNode) - { - return argumentSyntaxNode.GetExpression().GetParameterExpressionsFromArrayArgument()?.Select(syntax => syntax); } - protected override int AwaitExpressionRawKind { get; } = (int)SyntaxKind.AwaitExpression; + protected override SyntaxNode GetArgumentExpression(ArgumentSyntax argument) => argument.GetExpression(); - protected override IEnumerable GetArguments(ArgumentListSyntax argumentSyntax) + protected override SyntaxNode CreateArrayCreationExpression(SyntaxNode typeSyntax, IEnumerable elements) { - return argumentSyntax.Arguments; - } - - private static ArrayCreationExpressionSyntax CreateArrayCreationExpression( - SyntaxGenerator syntaxGenerator, - ITypeSymbol typeSymbol, - SeparatedSyntaxList initializers) - { - var typeNode = CreateTypeNode(syntaxGenerator, typeSymbol); - var syntaxes = CreateSingleLineLambdaExpressions(initializers); - - var initializer = CollectionInitializer(syntaxes); + var initializer = CollectionInitializer(SeparatedList(elements)); var arrayRankSpecifierSyntaxes = SingletonList(ArrayRankSpecifier()); - return ArrayCreationExpression(Token(SyntaxKind.NewKeyword), new SyntaxList(), typeNode, null, arrayRankSpecifierSyntaxes, initializer); - } - - private static SeparatedSyntaxList CreateSingleLineLambdaExpressions(SeparatedSyntaxList expressions) - { - var singleLineLambdaExpressionSyntaxes = expressions.Select(CreateSingleLineLambdaExpression); - - return SeparatedList(singleLineLambdaExpressionSyntaxes); - } - - private static SingleLineLambdaExpressionSyntax CreateSingleLineLambdaExpression(ExpressionSyntax expressionSyntax) - { - var separatedSyntaxList = SeparatedList(SingletonList(Parameter(ModifiedIdentifier(Identifier("x"))))); - var functionLambdaHeader = FunctionLambdaHeader( + return ArrayCreationExpression( + Token(SyntaxKind.NewKeyword), new SyntaxList(), - TokenList(), - ParameterList(separatedSyntaxList), - null); - - var lambdaExpression = SingleLineLambdaExpression( - SyntaxKind.SingleLineFunctionLambdaExpression, - functionLambdaHeader, - expressionSyntax.WithLeadingTrivia()); - return lambdaExpression; - } - - private static TypeSyntax CreateTypeNode(SyntaxGenerator syntaxGenerator, ITypeSymbol type) - { - var typeSyntax = (TypeSyntax)syntaxGenerator.TypeExpression(type); - return typeSyntax.WithAdditionalAnnotations(Simplifier.Annotation); + (TypeSyntax)typeSyntax, + null, + arrayRankSpecifierSyntaxes, + initializer); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/Extensions/ExpressionSyntaxExtensions.cs b/src/NSubstitute.Analyzers.VisualBasic/Extensions/ExpressionSyntaxExtensions.cs deleted file mode 100644 index d1e5f080..00000000 --- a/src/NSubstitute.Analyzers.VisualBasic/Extensions/ExpressionSyntaxExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.VisualBasic.Syntax; - -namespace NSubstitute.Analyzers.VisualBasic.Extensions; - -internal static class ExpressionSyntaxExtensions -{ - public static IList GetParameterExpressionsFromArrayArgument(this ExpressionSyntax expression) - { - switch (expression.Kind()) - { - case SyntaxKind.ArrayCreationExpression: - var initializer = ((ArrayCreationExpressionSyntax)expression).Initializer; - return initializer.Initializers.ToList(); - case SyntaxKind.CollectionInitializer: - return ((CollectionInitializerSyntax)expression).Initializers.ToList(); - default: - return null; - } - } -} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs index 10998fb6..744ab211 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs @@ -20,12 +20,6 @@ protected ReEntrantSetupCodeFixVerifier() protected override CodeFixProvider CodeFixProvider { get; } = new ReEntrantSetupCodeFixProvider(); [Theory] - [InlineData("CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "_ => CreateReEntrantSubstitute(), _ => CreateDefaultValue(), _ => 1")] - [InlineData("CreateReEntrantSubstitute(), new [] { CreateDefaultValue(), 1 }", "_ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] - [InlineData("CreateReEntrantSubstitute(), new int[] { CreateDefaultValue(), 1 }", "_ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] - [InlineData("returnThis: CreateReEntrantSubstitute()", "returnThis: _ => CreateReEntrantSubstitute()")] - [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new [] { CreateDefaultValue(), 1 }", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] - [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new int[] { CreateDefaultValue(), 1 }", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] public abstract Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments); [Fact] diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs index 7b15a9c6..66b951d0 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs @@ -1,10 +1,20 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared; +using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.ReEntrantSetupCodeFixProviderTests; public class ReturnsAsExtensionMethodTests : ReEntrantSetupCodeFixVerifier { + [Theory] + [InlineData("CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "_ => CreateReEntrantSubstitute(), _ => CreateDefaultValue(), _ => 1")] + [InlineData("CreateDefaultValue(), 1, CreateReEntrantSubstitute()", "_ => CreateDefaultValue(), _ => 1, _ => CreateReEntrantSubstitute()")] + [InlineData("CreateReEntrantSubstitute(), new [] { CreateDefaultValue(), 1 }", "_ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("CreateReEntrantSubstitute(), new int[] { CreateDefaultValue(), 1 }", "_ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("CreateDefaultValue(), new int[] { 1, CreateReEntrantSubstitute() }", "_ => CreateDefaultValue(), new System.Func[] { _ => 1, _ => CreateReEntrantSubstitute() }")] + [InlineData("returnThis: CreateReEntrantSubstitute()", "returnThis: _ => CreateReEntrantSubstitute()")] + [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new [] { CreateDefaultValue(), 1 }", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new int[] { CreateDefaultValue(), 1 }", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] public override async Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments) { var oldSource = $@"using NSubstitute; @@ -85,6 +95,7 @@ private int CreateDefaultValue() await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithReducedTypes_WhenGeneratingArrayParamsArgument() { var oldSource = @"using NSubstitute; @@ -163,6 +174,7 @@ private int CreateReEntrantSubstitute() await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithNonGenericCallInfo_WhenGeneratingArrayParamsArgument() { var oldSource = @"using NSubstitute; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs index 0164fb15..a1e31179 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,10 +1,25 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared; +using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.ReEntrantSetupCodeFixProviderTests; public class ReturnsAsOrdinaryMethodTests : ReEntrantSetupCodeFixVerifier { + [Theory] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "secondSubstitute.Id, _ => CreateReEntrantSubstitute(), _ => CreateDefaultValue(), _ => 1")] + [InlineData("secondSubstitute.Id, CreateDefaultValue(), 1, CreateReEntrantSubstitute()", "secondSubstitute.Id, _ => CreateDefaultValue(), _ => 1, _ => CreateReEntrantSubstitute()")] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), new [] { CreateDefaultValue(), 1 }", "secondSubstitute.Id, _ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), new int[] { CreateDefaultValue(), 1 }", "secondSubstitute.Id, _ => CreateReEntrantSubstitute(), new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("secondSubstitute.Id, CreateDefaultValue(), new [] { 1, CreateReEntrantSubstitute() }", "secondSubstitute.Id, _ => CreateDefaultValue(), new System.Func[] { _ => 1, _ => CreateReEntrantSubstitute() }")] + [InlineData("value: secondSubstitute.Id, returnThis: CreateReEntrantSubstitute()", "value: secondSubstitute.Id, returnThis: _ => CreateReEntrantSubstitute()")] + [InlineData("returnThis: CreateReEntrantSubstitute(), value: secondSubstitute.Id", "returnThis: _ => CreateReEntrantSubstitute(), value: secondSubstitute.Id")] + [InlineData("value: secondSubstitute.Id, returnThis: CreateReEntrantSubstitute(), returnThese: new [] { CreateDefaultValue(), 1 }", "value: secondSubstitute.Id, returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new [] { CreateDefaultValue(), 1 }, value: secondSubstitute.Id", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }, value: secondSubstitute.Id")] + [InlineData("returnThese: new [] { CreateDefaultValue(), 1 }, returnThis: CreateReEntrantSubstitute(), value: secondSubstitute.Id", "returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }, returnThis: _ => CreateReEntrantSubstitute(), value: secondSubstitute.Id")] + [InlineData("value: secondSubstitute.Id, returnThis: CreateReEntrantSubstitute(), returnThese: new int[] { CreateDefaultValue(), 1 }", "value: secondSubstitute.Id, returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }")] + [InlineData("returnThis: CreateReEntrantSubstitute(), returnThese: new int[] { CreateDefaultValue(), 1 }, value: secondSubstitute.Id", "returnThis: _ => CreateReEntrantSubstitute(), returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }, value: secondSubstitute.Id")] + [InlineData("returnThese: new int[] { CreateDefaultValue(), 1 }, returnThis: CreateReEntrantSubstitute(), value: secondSubstitute.Id", "returnThese: new System.Func[] { _ => CreateDefaultValue(), _ => 1 }, returnThis: _ => CreateReEntrantSubstitute(), value: secondSubstitute.Id")] public override async Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments) { var oldSource = $@"using NSubstitute; @@ -28,7 +43,7 @@ public interface IFoo public void Test() {{ var secondSubstitute = Substitute.For(); - SubstituteExtensions.Returns(secondSubstitute.Id, {arguments}); + SubstituteExtensions.Returns({arguments}); }} private int CreateReEntrantSubstitute() @@ -66,7 +81,7 @@ public interface IFoo public void Test() {{ var secondSubstitute = Substitute.For(); - SubstituteExtensions.Returns(secondSubstitute.Id, {rewrittenArguments}); + SubstituteExtensions.Returns({rewrittenArguments}); }} private int CreateReEntrantSubstitute() @@ -85,6 +100,7 @@ private int CreateDefaultValue() await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithReducedTypes_WhenGeneratingArrayParamsArgument() { var oldSource = @"using NSubstitute; @@ -163,6 +179,7 @@ private int CreateReEntrantSubstitute() await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithNonGenericCallInfo_WhenGeneratingArrayParamsArgument() { var oldSource = @"using NSubstitute; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs index cdf1445c..afa65b83 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReEntrantSetupCodeFixVerifier.cs @@ -15,10 +15,6 @@ public abstract class ReEntrantSetupCodeFixVerifier : VisualBasicCodeFixVerifier protected override CodeFixProvider CodeFixProvider { get; } = new ReEntrantSetupCodeFixProvider(); [Theory] - [InlineData("CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "Function(x) CreateReEntrantSubstitute(), Function(x) CreateDefaultValue(), Function(x) 1")] - [InlineData("CreateReEntrantSubstitute(), { CreateDefaultValue(), 1 }", "Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] - [InlineData("CreateReEntrantSubstitute(), New Integer() {CreateDefaultValue(), 1}", "Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] - [InlineData("returnThis:= CreateReEntrantSubstitute()", "returnThis:=Function(x) CreateReEntrantSubstitute()")] public abstract Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments); [Fact] diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs index 409d5baa..4b0682cb 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs @@ -1,10 +1,18 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared; +using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.ReEntrantSetupCodeFixProviderTests; public class ReturnsAsExtensionMethodTests : ReEntrantSetupCodeFixVerifier { + [Theory] + [InlineData("CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "Function(x) CreateReEntrantSubstitute(), Function(x) CreateDefaultValue(), Function(x) 1")] + [InlineData("CreateDefaultValue(), 1, CreateReEntrantSubstitute()", "Function(x) CreateDefaultValue(), Function(x) 1, Function(x) CreateReEntrantSubstitute()")] + [InlineData("CreateReEntrantSubstitute(), { CreateDefaultValue(), 1 }", "Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] + [InlineData("CreateDefaultValue(), { 1, CreateReEntrantSubstitute() }", "Function(x) CreateDefaultValue(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) 1, Function(x) CreateReEntrantSubstitute()}")] + [InlineData("CreateReEntrantSubstitute(), New Integer() {CreateDefaultValue(), 1}", "Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] + [InlineData("returnThis:= CreateReEntrantSubstitute()", "returnThis:=Function(x) CreateReEntrantSubstitute()")] public override async Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments) { var oldSource = $@"Imports NSubstitute @@ -73,6 +81,7 @@ End Namespace await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithReducedTypes_WhenGeneratingArrayParamsArgument() { var oldSource = @"Imports NSubstitute @@ -139,6 +148,7 @@ End Namespace await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithNonGenericCallInfo_WhenGeneratingArrayParamsArgument() { var oldSource = @"Imports NSubstitute diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs index 5721567d..c1700fcd 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReEntrantSetupCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,10 +1,19 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Tests.Shared; +using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.ReEntrantSetupCodeFixProviderTests; public class ReturnsAsOrdinaryMethodTests : ReEntrantSetupCodeFixVerifier { + [Theory] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), CreateDefaultValue(), 1", "secondSubstitute.Id, Function(x) CreateReEntrantSubstitute(), Function(x) CreateDefaultValue(), Function(x) 1")] + [InlineData("secondSubstitute.Id, CreateDefaultValue(), 1, CreateReEntrantSubstitute()", "secondSubstitute.Id, Function(x) CreateDefaultValue(), Function(x) 1, Function(x) CreateReEntrantSubstitute()")] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), { CreateDefaultValue(), 1 }", "secondSubstitute.Id, Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] + [InlineData("secondSubstitute.Id, CreateReEntrantSubstitute(), New Integer() {CreateDefaultValue(), 1}", "secondSubstitute.Id, Function(x) CreateReEntrantSubstitute(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) CreateDefaultValue(), Function(x) 1}")] + [InlineData("secondSubstitute.Id, CreateDefaultValue(), New Integer() {1, CreateReEntrantSubstitute()}", "secondSubstitute.Id, Function(x) CreateDefaultValue(), New System.Func(Of Core.CallInfo, Integer)() {Function(x) 1, Function(x) CreateReEntrantSubstitute()}")] + [InlineData("value:= secondSubstitute.Id, returnThis:= CreateReEntrantSubstitute()", "value:= secondSubstitute.Id, returnThis:=Function(x) CreateReEntrantSubstitute()")] + [InlineData("returnThis:= CreateReEntrantSubstitute(), value:= secondSubstitute.Id", "returnThis:=Function(x) CreateReEntrantSubstitute(), value:= secondSubstitute.Id")] public override async Task ReplacesArgumentExpression_WithLambda(string arguments, string rewrittenArguments) { var oldSource = $@"Imports NSubstitute @@ -23,7 +32,7 @@ End Interface Public Sub Test() Dim secondSubstitute = NSubstitute.Substitute.[For](Of IFoo)() - SubstituteExtensions.Returns(secondSubstitute.Id, {arguments}) + SubstituteExtensions.Returns({arguments}) End Sub Private Function CreateReEntrantSubstitute() As Integer @@ -55,7 +64,7 @@ End Interface Public Sub Test() Dim secondSubstitute = NSubstitute.Substitute.[For](Of IFoo)() - SubstituteExtensions.Returns(secondSubstitute.Id, {rewrittenArguments}) + SubstituteExtensions.Returns({rewrittenArguments}) End Sub Private Function CreateReEntrantSubstitute() As Integer @@ -73,6 +82,7 @@ End Namespace await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithReducedTypes_WhenGeneratingArrayParamsArgument() { var oldSource = @"Imports NSubstitute @@ -139,6 +149,7 @@ End Namespace await VerifyFix(oldSource, newSource); } + [Fact] public override async Task ReplacesArgumentExpression_WithLambdaWithNonGenericCallInfo_WhenGeneratingArrayParamsArgument() { var oldSource = @"Imports NSubstitute From 3880997199425a48a156f9455533e5a46396e6ef Mon Sep 17 00:00:00 2001 From: tpodolak Date: Tue, 6 Sep 2022 16:52:52 +0200 Subject: [PATCH 27/35] GH-153 - missing test cases --- ...gumentsForInterfaceCodeFixProviderTests.cs | 4 +- .../ReceivedAsOrdinaryMethodTests.cs | 14 ++ .../ForAsGenericMethodTests.cs | 15 +- .../ForAsNonGenericMethodTests.cs | 39 ++-- .../ForPartsOfMethodTests.cs | 16 +- .../SubstituteFactoryCreateMethodTests.cs | 33 ++-- ...bstituteFactoryCreatePartialMethodTests.cs | 38 ++-- ...stituteForInternalMemberCodeFixVerifier.cs | 24 ++- ...DoesMethodPrecededByOrdinaryMethodTests.cs | 112 +++++++++++- .../DoMethodPrecededByOrdinaryMethodTests.cs | 169 +++++++++++------- .../ReturnsAsOrdinaryMethodTests.cs | 120 ++++++++++++- .../ThrowsAsOrdinaryMethodTests.cs | 163 +++++++++++++---- .../ReturnsAsOrdinaryMethodTests.cs | 4 + ...SubstitutableMemberArgumentMatcherTests.cs | 4 + .../WhenAsOrdinaryMethodTests.cs | 2 + .../ReturnsAsOrdinaryMethodTests.cs | 10 +- .../ForAsNonGenericMethodTests.cs | 8 + .../ForPartsOfMethodTests.cs | 6 + .../SubstituteFactoryCreateMethodTests.cs | 6 + ...bstituteFactoryCreatePartialMethodTests.cs | 4 + .../CodeFixProviders/CodeFixVerifier.cs | 29 ++- ...stituteForInternalMemberCodeFixVerifier.cs | 8 +- ...rSuppressDiagnosticsCodeFixActionsTests.cs | 2 +- ...emberSuppressDiagnosticsCodeFixVerifier.cs | 2 +- .../ReturnsAsExtensionMethodTests.cs | 2 +- .../ReturnsAsOrdinaryMethodTests.cs | 2 +- ...naryMethodWithGenericTypeSpecifiedTests.cs | 2 +- ...ReturnsForAnyArgsAsExtensionMethodTests.cs | 2 +- .../ReturnsForAnyArgsAsOrdinaryMethodTests.cs | 2 +- ...sOrdinaryMethodWithGenericTypeSpecified.cs | 2 +- .../ReceivedAsOrdinaryMethodTests.cs | 8 + .../ForAsGenericMethodTests.cs | 16 +- .../ForAsNonGenericMethodTests.cs | 39 ++-- .../ForPartsOfMethodTests.cs | 16 +- .../SubstituteFactoryCreateMethodTests.cs | 39 ++-- ...bstituteFactoryCreatePartialMethodTests.cs | 39 ++-- ...stituteForInternalMemberCodeFixVerifier.cs | 24 ++- ...DoesMethodPrecededByOrdinaryMethodTests.cs | 77 +++++++- .../DoMethodPrecededByOrdinaryMethodTests.cs | 81 ++++++++- .../ReturnsAsOrdinaryMethodTests.cs | 85 ++++++++- .../ThrowsAsOrdinaryMethodsTests.cs | 51 +++++- .../ReturnsAsOrdinaryMethodTests.cs | 4 + .../ThrowsAsOrdinaryMethodTests.cs | 4 + ...SubstitutableMemberArgumentMatcherTests.cs | 121 ++++++++++--- .../WhenAsOrdinaryMethodTests.cs | 7 +- .../ForAsGenericMethodTests.cs | 4 +- .../ForAsNonGenericMethodTests.cs | 4 + .../ForPartsOfMethodTests.cs | 2 + .../SubstituteFactoryCreateMethodTests.cs | 6 + ...bstituteFactoryCreatePartialMethodTests.cs | 12 +- .../ReceivedAsOrdinaryMethodTests.cs | 39 +++- 51 files changed, 1236 insertions(+), 286 deletions(-) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs (97%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs (95%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsAsExtensionMethodTests.cs (98%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsAsOrdinaryMethodTests.cs (98%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs (98%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsForAnyArgsAsExtensionMethodTests.cs (98%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsForAnyArgsAsOrdinaryMethodTests.cs (98%) rename tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/{NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests => NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests}/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs (98%) diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs index 97fedd16..d3227043 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests/ConstructorArgumentsForInterfaceCodeFixProviderTests.cs @@ -30,7 +30,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(1, 2, 3); - var otherSubstitute = NSubstitute.Substitute.For(constructorArguments: new [] { 1, 2, 3 }); + var otherSubstitute = NSubstitute.Substitute.For(new [] { 1, 2, 3 }); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: new [] { 1, 2, 3 }); } } }"; @@ -48,6 +49,7 @@ public void Test() { var substitute = NSubstitute.Substitute.For(); var otherSubstitute = NSubstitute.Substitute.For(); + var yetAnotherSubstitute = NSubstitute.Substitute.For(); } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs index 1010e560..de2baf49 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs @@ -84,7 +84,14 @@ public void Test() Received.InOrder(() => { SubstituteExtensions.Received(substitute, 1).Bar(); + SubstituteExtensions.Received(substitute: substitute, requiredNumberOfCalls: 1).Bar(); + SubstituteExtensions.Received(requiredNumberOfCalls: 1, substitute: substitute).Bar(); SubstituteExtensions.Received(substitute, 1).Bar(Arg.Any()); + SubstituteExtensions.Received(substitute: substitute, requiredNumberOfCalls: 1).Bar(Arg.Any()); + SubstituteExtensions.Received(requiredNumberOfCalls: 1, substitute: substitute).Bar(Arg.Any()); + SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1).Bar(Arg.Any()); + SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, requiredNumberOfCalls: 1).Bar(Arg.Any()); + SubstituteExtensions.ReceivedWithAnyArgs(requiredNumberOfCalls: 1, substitute: substitute).Bar(Arg.Any()); }); } } @@ -109,6 +116,13 @@ public void Test() Received.InOrder(() => { substitute.Bar(); + substitute.Bar(); + substitute.Bar(); + substitute.Bar(Arg.Any()); + substitute.Bar(Arg.Any()); + substitute.Bar(Arg.Any()); + substitute.Bar(Arg.Any()); + substitute.Bar(Arg.Any()); substitute.Bar(Arg.Any()); }); } diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs index acc8b21d..234aaad7 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForAsGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -50,8 +48,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -89,8 +86,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"using System.Reflection; using NSubstitute; @@ -131,8 +127,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -178,7 +173,6 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"using NSubstitute; @@ -199,7 +193,6 @@ public void Test() await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"using NSubstitute; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs index e3c41785..108ed0ff 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForAsNonGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -22,6 +20,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,15 +43,16 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -65,6 +66,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -83,14 +86,15 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"using System.Reflection; using NSubstitute; @@ -106,6 +110,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -125,14 +131,15 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -150,6 +157,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -172,13 +181,14 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"using NSubstitute; @@ -199,7 +209,6 @@ public void Test() await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"using NSubstitute; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs index c783b6cc..2c72a2a4 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForPartsOfMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -50,8 +48,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -89,8 +86,8 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( + int diagnosticIndex) { var oldSource = @"using System.Reflection; using NSubstitute; @@ -131,8 +128,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -178,7 +174,6 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"using NSubstitute; @@ -199,7 +194,6 @@ public void Test() await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"using NSubstitute; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs index 2123946c..1a671367 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; public class SubstituteFactoryCreateMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -22,6 +20,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,15 +43,16 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -89,8 +90,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"using System.Reflection; using NSubstitute.Core; @@ -106,6 +106,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -125,14 +127,15 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -150,6 +153,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -172,13 +177,14 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"using NSubstitute.Core; @@ -199,7 +205,6 @@ public void Test() await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"using NSubstitute.Core; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs index b18a5ad0..a7512798 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -5,8 +5,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class SubstituteFactoryCreatePartialMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -22,6 +21,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,15 +44,16 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -65,6 +67,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -83,14 +87,15 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"using System.Reflection; using NSubstitute.Core; @@ -106,6 +111,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -125,14 +132,15 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -150,6 +158,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -172,13 +182,14 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo.Bar)}, null); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"using NSubstitute.Core; @@ -199,7 +210,6 @@ public void Test() await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"using NSubstitute.Core; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs index 422152bd..cfff275c 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs @@ -1,27 +1,43 @@ +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.CSharp.CodeFixProviders; using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; +using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; public abstract class SubstituteForInternalMemberCodeFixVerifier : CSharpCodeFixVerifier, ISubstituteForInternalMemberCodeFixVerifier { + public static IEnumerable DiagnosticIndicesTestCases => + Enumerable.Range(0, 3).Select(item => new object[] { item }); + protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; } = new SubstituteAnalyzer(); protected override CodeFixProvider CodeFixProvider { get; } = new SubstituteForInternalMemberCodeFixProvider(); - public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); + [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); + [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2(); } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs index 01b9965a..a2002e02 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -207,6 +208,37 @@ public void Test() }}); }}); + SubstituteExtensions.Returns(value: substitute.FooBaz(Arg.Any(), Arg.Any()), returnThis: 1) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + }}); + + SubstituteExtensions.Returns(returnThis: 1, value: substitute.FooBaz(Arg.Any(), Arg.Any())) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + }}); }} }} }}"; @@ -570,6 +602,30 @@ public void Test() return 1; }}); }}); + SubstituteExtensions.Returns(value: substitute.FooBaz(Arg.Any()), returnThis: 1) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + + return 1; + }}); + }}); + SubstituteExtensions.Returns(returnThis: 1, value: substitute.FooBaz(Arg.Any())) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + + return 1; + }}); + }}); }} }} @@ -616,6 +672,40 @@ public void Test() return 1; }}); }}); + SubstituteExtensions.Returns(value: substitute.FooBaz(Arg.Any(), Arg.Any()), returnThis: 1) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return 1; + }}); + }}); + SubstituteExtensions.Returns(returnThis: 1, value: substitute.FooBaz(Arg.Any(), Arg.Any())) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return 1; + }}); + }}); }} }} @@ -628,7 +718,7 @@ public void Test() "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -720,6 +810,26 @@ public void Test() return innerCallInfo.Arg(); }}); }}); + SubstituteExtensions.Returns(value: substitute.FooBaz(Arg.Any()), returnThis: 1) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + }}); + SubstituteExtensions.Returns(returnThis: 1, value: substitute.FooBaz(Arg.Any())) + .{method}(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + }}); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs index c4eb1a00..cc68fce6 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -84,14 +85,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -131,14 +124,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -220,6 +205,34 @@ public void Test() return 1; }}); }}); + {method}(substitute: substitute, substituteCall: sub => sub.FooBaz(Arg.Any(), Arg.Any())).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + }}); + {method}(substituteCall: sub => sub.FooBaz(Arg.Any(), Arg.Any()), substitute: substitute).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + }}); }} }} @@ -266,14 +279,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -328,14 +333,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -482,14 +479,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -570,14 +559,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -618,7 +599,28 @@ public void Test() return 1; }}); }}); + {method}(substitute: substitute, substituteCall: sub => sub.FooBaz(Arg.Any())).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + + return 1; + }}); + }}); + {method}(substituteCall: sub => sub.FooBaz(Arg.Any()), substitute: substitute).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + return 1; + }}); + }}); }} }} }}"; @@ -663,6 +665,38 @@ public void Test() return 1; }}); }}); + {method}(substitute: substitute, substituteCall: sub => sub.FooBaz(Arg.Any(), Arg.Any())).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return 1; + }}); + }}); + {method}(substituteCall: sub => sub.FooBaz(Arg.Any(), Arg.Any()), substitute: substitute).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return 1; + }}); + }}); }} }} @@ -675,7 +709,7 @@ public void Test() "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -735,8 +769,7 @@ public void Test() await VerifyNoDiagnostic(source); } - public override async Task ReportsNoDiagnostic_WhenAccessingArgumentByTypeInInvocationForNestedCall( - string method) + public override async Task ReportsNoDiagnostic_WhenAccessingArgumentByTypeInInvocationForNestedCall(string method) { var source = $@"using System; using NSubstitute; @@ -767,6 +800,24 @@ public void Test() return innerCallInfo.Arg(); }}); }}); + {method}(substitute: substitute, substituteCall: sub => sub.FooBaz(Arg.Any())).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + }}); + {method}(substituteCall: sub => sub.FooBaz(Arg.Any()), substitute: substitute).Do(outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + otherSubstitute.Bar(Arg.Any()).Returns(innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + }}); }} }} }}"; @@ -811,14 +862,6 @@ public void Test() {{ {argAccess} }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = {call}; }}).Do(callInfo => - {{ - {argAccess} - }}); - {method}(substituteCall: substitute => {{var _ = {call}; }}, substitute: sub).Do(callInfo => - {{ - {argAccess} - }}); }} }} }}"; @@ -972,14 +1015,6 @@ public void Test() {{ callInfo[0] = 1; }}); - {method}(substitute: sub, substituteCall: substitute => {{var _ = substitute.Bar(out value); }}).Do(callInfo => - {{ - callInfo[0] = 1; - }}); - {method}(substituteCall: substitute => {{var _ = substitute.Bar(out value); }}, substitute: sub).Do(callInfo => - {{ - callInfo[0] = 1; - }}); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index fa16f501..bd8a4a87 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -217,6 +218,38 @@ public void Test() return 1; }}); + {method}(value: substitute.FooBaz(Arg.Any(), Arg.Any()), returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + + return 1; + }}); + {method}(returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return 1; + }}); + + return 1; + }}, value: substitute.FooBaz(Arg.Any(), Arg.Any())); }} }} @@ -604,6 +637,34 @@ public void Test() return 1; }}); + {method}(value: substitute.FooBaz(Arg.Any()), returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + var z = outerCallInfo.Arg(); + + return 1; + }}); + + return 1; + }}); + {method}(returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + var z = outerCallInfo.Arg(); + + return 1; + }}); + + return 1; + }}, value: substitute.FooBaz(Arg.Any())); }} }} }}"; @@ -650,7 +711,42 @@ public void Test() return 1; }}); + {method}(value: substitute.FooBaz(Arg.Any(), Arg.Any()), returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return 1; + }}); + + return 1; + }}); + {method}(returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + return 1; + }}); + + return 1; + }}, value: substitute.FooBaz(Arg.Any(), Arg.Any())); }} }} }}"; @@ -662,7 +758,7 @@ public void Test() "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -758,6 +854,28 @@ public void Test() return 1; }}); + {method}(value: substitute.FooBaz(Arg.Any()), returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + + return 1; + }}); + {method}(returnThis: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + return innerCallInfo.Arg(); + }}); + + return 1; + }}, value: substitute.FooBaz(Arg.Any())); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index 09889a5a..c382b0a5 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -46,11 +47,6 @@ public void Test() {argAccess} return new Exception(); }}); - {method}(value: returnedValue, createException: callInfo => - {{ - {argAccess} - return new Exception(); - }}); {method}(createException: callInfo => {{ {argAccess} @@ -139,11 +135,6 @@ public void Test() {argAccess} return new Exception(); }}); - {method}(value: {call}, createException: callInfo => - {{ - {argAccess} - return new Exception(); - }}); {method}(createException: callInfo => {{ {argAccess} @@ -184,6 +175,16 @@ public void Test() {argAccess} return new Exception(); }}); + {method}(value: {call}, createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}); + {method}(createException: callInfo => + {{ + {argAccess} + return new Exception(); + }}, value: {call}); }} }} }}"; @@ -230,6 +231,38 @@ public void Test() return new Exception(); }}); + {method}(value: substitute.FooBaz(Arg.Any(), Arg.Any()), createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return new Exception(); + }}); + + return new Exception(); + }}); + {method}(createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.ArgAt(1); + var y = outerCallInfo[1]; + + var xx = innerCallInfo.ArgAt(0); + var yy = innerCallInfo[0]; + + return new Exception(); + }}); + + return new Exception(); + }}, value: substitute.FooBaz(Arg.Any(), Arg.Any())); }} }} @@ -276,11 +309,6 @@ public void Test() {argAccess} return new Exception(); }}); - {method}(value: {call}, createException: callInfo => - {{ - {argAccess} - return new Exception(); - }}); {method}(createException: callInfo => {{ {argAccess} @@ -637,6 +665,34 @@ public void Test() return new Exception(); }}); + {method}(value: substitute.FooBaz(Arg.Any()), createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + var z = outerCallInfo.Arg(); + + return new Exception(); + }}); + + return new Exception(); + }}); + {method}(createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.Arg()|]; + var y = [|innerCallInfo.Arg()|]; + var z = outerCallInfo.Arg(); + + return new Exception(); + }}); + + return new Exception(); + }}, value: substitute.FooBaz(Arg.Any())); }} }} }}"; @@ -685,6 +741,42 @@ public void Test() return new Exception(); }}); + {method}(value: substitute.FooBaz(Arg.Any(), Arg.Any()), createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return new Exception(); + }}); + + return new Exception(); + }}); + {method}(createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = [|outerCallInfo.ArgAt(2)|]; + var y = [|outerCallInfo[2]|]; + var z = outerCallInfo[1]; + + var xx = [|innerCallInfo.ArgAt(1)|]; + var yy = [|innerCallInfo[1]|]; + var zz = innerCallInfo[0]; + + return new Exception(); + }}); + + return new Exception(); + }}, value: substitute.FooBaz(Arg.Any(), Arg.Any())); }} }} @@ -697,7 +789,7 @@ public void Test() "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -798,6 +890,30 @@ public void Test() return new Exception(); }}); + {method}(value: substitute.FooBaz(Arg.Any()), createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + var z = innerCallInfo.Arg(); + return new Exception(); + }}); + + return new Exception(); + }}); + {method}(createException: outerCallInfo => + {{ + var otherSubstitute = NSubstitute.Substitute.For(); + {method}(otherSubstitute.Bar(Arg.Any()), innerCallInfo => + {{ + var x = outerCallInfo.Arg(); + var z = innerCallInfo.Arg(); + return new Exception(); + }}); + + return new Exception(); + }}, value: substitute.FooBaz(Arg.Any())); }} }} @@ -844,11 +960,6 @@ public void Test() {argAccess} return new Exception(); }}); - {method}(value: {call}, createException: callInfo => - {{ - {argAccess} - return new Exception(); - }}); {method}(createException: callInfo => {{ {argAccess} @@ -984,11 +1095,6 @@ public void Test() callInfo[0] = 1; return new Exception(); }}); - {method}(value: substitute.Bar(ref value), createException: callInfo => - {{ - callInfo[0] = 1; - return new Exception(); - }}); {method}(createException: callInfo => {{ callInfo[0] = 1; @@ -1156,11 +1262,6 @@ public void Test() callInfo[0] = {right}; return new Exception(); }}); - {method}(value: substitute.Bar(out value), createException: callInfo => - {{ - callInfo[0] = {right}; - return new Exception(); - }}); {method}(createException: callInfo => {{ callInfo[0] = {right}; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 22dc04b5..12408b24 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -584,7 +584,11 @@ public void Test() {{ var substitute = NSubstitute.Substitute.For>(); {method}(substitute.Bar, 1); + {method}(value: substitute.Bar, returnThis: 1); + {method}(returnThis: 1, value: substitute.Bar); {method}([|substitute.FooBar|], 1); + {method}(value: [|substitute.FooBar|], returnThis: 1); + {method}(returnThis: 1, value: [|substitute.FooBar|]); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs index 656812cd..16789ad2 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs @@ -771,6 +771,10 @@ public void Test() var substitute = NSubstitute.Substitute.For(); substitute.Bar({arg}, {arg}); substitute.Bar([|{arg}|]); + substitute.When(x => x.Bar([|{arg}|])); + SubstituteExtensions.When(substitute, x => x.Bar([|{arg}|])); + SubstituteExtensions.When(substitute: substitute, substituteCall: x => x.Bar([|{arg}|])); + SubstituteExtensions.When(substituteCall: x => x.Bar([|{arg}|]), substitute: substitute); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs index ae6d67f5..e9145c48 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -382,6 +382,8 @@ public void Test() {{ Foo substitute = null; {method}(substitute, {whenAction}, 1); + {method}(substituteCall: {whenAction}, substitute: substitute, x: 1); + {method}(substitute: substitute, substituteCall: {whenAction}, x: 1); }} }} }}"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 384475ab..1feed621 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -197,6 +197,8 @@ public void Test() {{ var substitute = Substitute.For(); {method}(substitute.Bar(), [|ReturnThis()|], [|OtherReturn()|]); + {method}(value: substitute.Bar(), returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|]); + {method}(returnThis: [|ReturnThis()|], returnThese: [|OtherReturn()|], value: substitute.Bar()); }} private int ReturnThis() @@ -229,10 +231,14 @@ private int OtherNestedReturnThis() var diagnosticMessages = new[] { + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn()).", + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", + $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => ReturnThis()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => OtherReturn()).", $"{plainMethodName}() is set with a method that itself calls {plainMethodName}. This can cause problems with NSubstitute. Consider replacing with a lambda: {plainMethodName}(x => NestedReturnThis())." - }.Repeat(2).ToList(); + }; var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(Descriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); @@ -472,6 +478,7 @@ public void Test() var substitute = Substitute.For(); {method}(substitute.Bar(), {firstReturn}, {secondReturn}); {method}(value: substitute.Bar(), returnThis: {firstReturn}, returnThese: {secondReturn}); + {method}(returnThis: {firstReturn}, returnThese: {secondReturn}, value: substitute.Bar()); }} @@ -645,6 +652,7 @@ public void Test() var array = new[] {{ ReturnThis() }}; {method}(substitute.Bar(), 1, array); {method}(value: substitute.Bar(), returnThis: 1, returnThese: array); + {method}(returnThis: 1, returnThese: array, value: substitute.Bar()); }} private int ReturnThis() diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs index 6705c746..a0a0301e 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs @@ -669,6 +669,8 @@ public class FooTests {{ public void Test() {{ + var substitute = NSubstitute.Substitute.For(new [] {{ typeof(Foo) }}, {invocationValues}); + var otherSubstitute = NSubstitute.Substitute.For(typesToProxy: new [] {{ typeof(Foo) }}, constructorArguments: {invocationValues}); var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: {invocationValues}, typesToProxy: new [] {{ typeof(Foo) }}); }} }} @@ -713,6 +715,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new [] { typeof(Foo) }, new object[] { 1 }); + var otherSubstitute = Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 }); + var yetAnotherSubstitute = Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -737,6 +741,8 @@ public class FooTests public void Test() { var substitute = Substitute.For(new [] { typeof(Foo) }, new object[] { 1, 2, 3 }); + var otherSubstitute = Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1, 2, 3 }); + var yetAnotherSubstitute = Substitute.For(constructorArguments: new object[] { 1, 2, 3 }, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -761,6 +767,8 @@ public class FooTests public void Test() { var substitute = [|Substitute.For(new [] { typeof(Foo) }, new object[] { 1 })|]; + var otherSubstitute = [|Substitute.For(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|Substitute.For(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs index a31167a3..f809311e 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs @@ -457,6 +457,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.ForPartsOf(1, 2, 3); + var otherSubstitute = NSubstitute.Substitute.ForPartsOf(new object[] { 1, new int[] { 2, 3 } }); + var yetAnotherSubstitute = NSubstitute.Substitute.ForPartsOf(constructorArguments: new object[] { 1, new int[] { 2, 3 } }); } } }"; @@ -481,6 +483,10 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.ForPartsOf(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.ForPartsOf(new [] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.ForPartsOf(new [] { 1, 2 })|]; + var someOtherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: new [] { 1 })|]; + var yetSomeOtherSubstitute = [|NSubstitute.Substitute.ForPartsOf(constructorArguments: new [] { 1, 2 })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs index ad8b4e67..352bec88 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs @@ -686,6 +686,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(Foo) }, new object[] { 1 }); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 }); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -711,6 +713,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(Foo) }, new object[] { 1, 2, 3 }); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1, 2, 3 }); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1, 2, 3 }, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -736,6 +740,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.Create(new [] { typeof(Foo) }, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs index eb82cf51..eb047de1 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -527,6 +527,8 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new [] { typeof(Foo) }, new object[] { 1, 2, 3 }); + var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1, 2, 3 }); + var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] { 1, 2, 3 }, typesToProxy: new [] { typeof(Foo) }); } } }"; @@ -552,6 +554,8 @@ public class FooTests public void Test() { var substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(new [] { typeof(Foo) }, new object[] { 1 })|]; + var otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new [] { typeof(Foo) }, constructorArguments: new object[] { 1 })|]; + var yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: new object[] { 1 }, typesToProxy: new [] { typeof(Foo) })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs index 911b3224..51384e6e 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs @@ -25,9 +25,34 @@ protected CodeFixVerifier(WorkspaceFactory workspaceFactory) protected abstract DiagnosticAnalyzer DiagnosticAnalyzer { get; } + protected Task VerifyFix( + string oldSource, + string newSource) => + VerifyFix(oldSource, newSource, null, NSubstituteVersion.Latest); + + protected Task VerifyFix( + string oldSource, + string newSource, + int codeFixIndex) => + VerifyFix(oldSource, newSource, codeFixIndex, NSubstituteVersion.Latest); + + protected Task VerifyFix( + string oldSource, + string newSource, + NSubstituteVersion version) => + VerifyFix(oldSource, newSource, diagnosticIndex: null, codeFixIndex: null, version); + + protected Task VerifyFix( + string oldSource, + string newSource, + int? codeFixIndex = null, + NSubstituteVersion version = NSubstituteVersion.Latest) => + VerifyFix(oldSource, newSource, null, codeFixIndex, version); + protected async Task VerifyFix( string oldSource, string newSource, + int? diagnosticIndex = null, int? codeFixIndex = null, NSubstituteVersion version = NSubstituteVersion.Latest) { @@ -49,12 +74,12 @@ protected async Task VerifyFix( project.AnalyzerOptions); var previousAnalyzerDiagnostics = analyzerDiagnostics; - var attempts = analyzerDiagnostics.Length; + var attempts = !diagnosticIndex.HasValue ? analyzerDiagnostics.Length : 1; for (var i = 0; i < attempts; ++i) { var actions = new List(); - var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); + var context = new CodeFixContext(document, analyzerDiagnostics[diagnosticIndex ?? 0], (a, _) => actions.Add(a), CancellationToken.None); await CodeFixProvider.RegisterCodeFixesAsync(context); if (!actions.Any()) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs index f349df15..00e76875 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs @@ -4,13 +4,13 @@ namespace NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; public interface ISubstituteForInternalMemberCodeFixVerifier { - Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); + Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); - Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); + Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); - Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); + Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); - Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); + Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs similarity index 97% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs index 0763979a..f71efa29 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests.cs @@ -7,7 +7,7 @@ using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; using Xunit; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class NonSubstitutableMemberSuppressDiagnosticsCodeFixActionsTests : VisualBasicCodeFixActionsVerifier, INonSubstitutableMemberSuppressDiagnosticsCodeFixActionsVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs similarity index 95% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs index 6c750d55..5dc1947e 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier.cs @@ -6,7 +6,7 @@ using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; using Xunit; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public abstract class NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier : VisualBasicSuppressDiagnosticSettingsVerifier, INonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs index 32dd5d2c..fbd7fb95 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsAsExtensionMethodTests : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs index eabecaf1..042ab433 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsAsOrdinaryMethodTests : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs index b3cc0e40..0e6f3769 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsAsOrdinaryMethodWithGenericTypeSpecifiedTests : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs index 47a6a4ad..11d3c34d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsExtensionMethodTests.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsForAnyArgsAsExtensionMethodTests : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs index e6370b7f..80dcf4f5 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodTests.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsForAnyArgsAsOrdinaryMethodTests : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs similarity index 98% rename from tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs rename to tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs index e8c463a6..40ddd3ef 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests/ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using NSubstitute.Analyzers.Shared; -namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberAnalyzerSuppressDiagnosticsCodeFixProviderTests; +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.NonSubstitutableMemberSuppressDiagnosticsCodeFixProviderTests; public class ReturnsForAnyArgsAsOrdinaryMethodWithGenericTypeSpecified : NonSubstitutableMemberSuppressDiagnosticsCodeFixVerifier { diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs index ba14420f..cd71c13e 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/ReceivedInReceivedInOrderCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs @@ -70,7 +70,11 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() NSubstitute.Received.InOrder(Function() SubstituteExtensions.Received(substitute, 1).Bar() + SubstituteExtensions.Received(substitute:= substitute, requiredNumberOfCalls:= 1).Bar() + SubstituteExtensions.Received(requiredNumberOfCalls:= 1, substitute:= substitute).Bar() SubstituteExtensions.Received(substitute, 1).Bar(Arg.Any(Of Integer)()) + SubstituteExtensions.Received(substitute:= substitute, requiredNumberOfCalls:= 1).Bar(Arg.Any(Of Integer)()) + SubstituteExtensions.Received(requiredNumberOfCalls:= 1, substitute:= substitute).Bar(Arg.Any(Of Integer)()) End Function) End Sub End Class @@ -90,6 +94,10 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() NSubstitute.Received.InOrder(Function() substitute.Bar() + substitute.Bar() + substitute.Bar() + substitute.Bar(Arg.Any(Of Integer)()) + substitute.Bar(Arg.Any(Of Integer)()) substitute.Bar(Arg.Any(Of Integer)()) End Function) End Sub diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs index 300abe3d..bfee457b 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForAsGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute @@ -42,8 +40,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -75,8 +72,8 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( + int diagnosticIndex) { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -110,8 +107,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -147,7 +143,6 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"Imports NSubstitute.Core @@ -166,7 +161,6 @@ End Namespace await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs index ac7cc43e..598ca5b8 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForAsNonGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -18,6 +16,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,16 +34,17 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -54,6 +55,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -68,15 +71,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -88,6 +92,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -103,15 +109,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -124,6 +131,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -140,14 +149,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"Imports NSubstitute.Core @@ -166,7 +176,6 @@ End Namespace await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs index 7ef3b321..a7de9762 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public class ForPartsOfMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute @@ -42,8 +40,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -75,8 +72,8 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( + int diagnosticIndex) { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -110,8 +107,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -147,7 +143,6 @@ End Namespace await VerifyFix(oldSource, newSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"Imports NSubstitute.Core @@ -166,7 +161,6 @@ End Namespace await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs index 6d08bc0d..143fda60 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public class SubstituteFactoryCreateMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -18,6 +16,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,16 +34,17 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -54,6 +55,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -68,15 +71,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -88,6 +92,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -103,15 +109,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -124,6 +131,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -140,14 +149,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"Imports NSubstitute.Core @@ -166,7 +176,6 @@ End Namespace await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs index 7c825a6e..59632db5 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -1,12 +1,10 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public class SubstituteFactoryCreatePartialMethodTests : SubstituteForInternalMemberCodeFixVerifier { - [Fact] - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -18,6 +16,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,16 +34,17 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -54,6 +55,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -68,15 +71,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -88,6 +92,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -103,15 +109,16 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) { var oldSource = @"Imports NSubstitute.Core @@ -124,6 +131,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -140,14 +149,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo.Bar)}, Nothing) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource); + await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() { var oldSource = @"Imports NSubstitute.Core @@ -168,7 +178,6 @@ End Namespace await VerifyFix(oldSource, oldSource); } - [Fact] public override async Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs index 70ff94aa..105fcda2 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs @@ -1,27 +1,43 @@ +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; using NSubstitute.Analyzers.VisualBasic.CodeFixProviders; using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; +using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.SubstituteForInternalMemberCodeFixProviderTests; public abstract class SubstituteForInternalMemberCodeFixVerifier : VisualBasicCodeFixVerifier, ISubstituteForInternalMemberCodeFixVerifier { + public static IEnumerable DiagnosticIndicesTestCases => + Enumerable.Range(0, 3).Select(item => new object[] { item }); + protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; } = new SubstituteAnalyzer(); protected override CodeFixProvider CodeFixProvider { get; } = new SubstituteForInternalMemberCodeFixProvider(); - public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); + [Theory] + [MemberData(nameof(DiagnosticIndicesTestCases))] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); + [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); + [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenInternalsVisibleToAppliedToDynamicProxyGenAssembly2(); } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs index 676af167..eeab7505 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/AndDoesMethodPrecededByOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -162,6 +163,26 @@ Public Sub Test() Return 1 End Function) End Function) + SubstituteExtensions.Returns(value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)()), returnThis:= 1).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + End Function) + SubstituteExtensions.Returns(returnThis:= 1, value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)())).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; @@ -198,6 +219,30 @@ Public Sub Test() Return 1 End Function) End Function) + SubstituteExtensions.Returns(value:=substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)()), returnThis:= 1).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any (Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt(Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt(Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + End Function) + SubstituteExtensions.Returns(returnThis:= 1, value:=substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)())).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any (Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt(Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt(Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; @@ -209,7 +254,7 @@ End Class "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -533,6 +578,20 @@ Public Sub Test() Return innerCallInfo.Arg(Of Integer)() End Function) End Function) + SubstituteExtensions.Returns(value:= substitute.FooBaz(Arg.Any(Of String)()), returnThis:= 1).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + End Function) + SubstituteExtensions.Returns(returnThis:= 1, value:= substitute.FooBaz(Arg.Any(Of String)())).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + End Function) End Sub End Class End Namespace"; @@ -816,6 +875,22 @@ Public Sub Test() Return 1 End Function) End Function) + SubstituteExtensions.Returns(value:= substitute.FooBaz(Arg.Any(Of Integer)()), returnThis:= 1).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + End Function) + SubstituteExtensions.Returns(returnThis:= 1, value:= substitute.FooBaz(Arg.Any(Of Integer)())).{method}(Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs index 2d459db8..e4eb5ab4 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/DoMethodPrecededByOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -187,6 +188,28 @@ Public Sub Test() Return 1 End Function) End Function) + {method}(substitute:= substitute, substituteCall:= Function([sub]) [sub].FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)())).[Do]( + Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + otherSubstitute.Bar(Arg.Any (Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt (Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt (Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + End Function) + {method}(substituteCall:= Function([sub]) [sub].FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)()), substitute:= substitute).[Do]( + Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + otherSubstitute.Bar(Arg.Any (Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt (Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt (Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; @@ -224,6 +247,32 @@ Public Sub Test() Return 1 End Function) End Function) + {method}(substitute:= substitute, substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)())).[Do]( + Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt(Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt(Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + End Function) + {method}(substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)()), substitute:= substitute).[Do]( + Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt(Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt(Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; @@ -235,7 +284,7 @@ End Class "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -608,6 +657,20 @@ Public Sub Test() Return innerCallInfo.Arg(Of Integer)() End Function) End Function) + {method}(substitute:= substitute, substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of String)())).[Do](Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + End Function) + {method}(substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of String)()), substitute:= substitute).[Do](Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + End Function) End Sub End Class End Namespace"; @@ -939,6 +1002,22 @@ Public Sub Test() Return 1 End Function) End Function) + {method}(substitute:= substitute, substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of Integer)())).[Do](Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + End Function) + {method}(substituteCall:= Sub([sub]) [sub].FooBaz(Arg.Any(Of Integer)()), substitute:= substitute).[Do](Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + otherSubstitute.Bar(Arg.Any(Of Integer)()).Returns(Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + End Function) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 06f04449..3bfe2df8 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -172,6 +173,28 @@ Return 1 End Function) Return 1 End Function) + {method}(value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)()), returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + Return 1 + End Function) + {method}(returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return 1 + End Function) + Return 1 + End Function, value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)())) End Sub End Class End Namespace"; @@ -209,6 +232,32 @@ Return 1 End Function) Return 1 End Function) + {method}(value:= substitute.FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)()), returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt (Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt (Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + Return 1 + End Function) + {method}(returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt (Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt (Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return 1 + End Function) + Return 1 + End Function, value:= substitute.FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)())) End Sub End Class End Namespace"; @@ -220,7 +269,7 @@ End Class "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); @@ -568,6 +617,22 @@ Return innerCallInfo.Arg(Of Integer)() End Function) Return 1 End Function) + {method}(value:= substitute.FooBaz(Arg.Any (Of String)()), returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any(Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + Return 1 + End Function) + {method}(returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any(Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.Arg(Of String)() + Return innerCallInfo.Arg(Of Integer)() + End Function) + Return 1 + End Function, value:= substitute.FooBaz(Arg.Any (Of String)())) End Sub End Class End Namespace"; @@ -876,6 +941,24 @@ Return 1 End Function) Return 1 End Function) + {method}(value:= substitute.FooBaz(Arg.Any(Of Integer)()), returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any(Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + Return 1 + End Function) + {method}(returnThis:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any(Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.Arg(Of String)()|] + Dim y = [|innerCallInfo.Arg(Of String)()|] + Return 1 + End Function) + Return 1 + End Function, value:= substitute.FooBaz(Arg.Any(Of Integer)())) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodsTests.cs index 12b704de..3ff2af8a 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/CallInfoAnalyzerTests/ThrowsAsOrdinaryMethodsTests.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using MoreLinq; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; @@ -185,6 +186,28 @@ Return New Exception() End Function) Return New Exception() End Function) + {method}(value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)()), createException:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return New Exception() + End Function) + Return New Exception() + End Function) + {method}(createException:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = outerCallInfo.ArgAt(Of Integer)(1) + Dim y = outerCallInfo(1) + Dim xx = innerCallInfo.ArgAt(Of Integer)(0) + Dim yy = innerCallInfo(0) + Return New Exception() + End Function) + Return New Exception() + End Function, value:= substitute.FooBaz(Arg.Any(Of Integer)(), Arg.Any(Of Integer)())) End Sub End Class End Namespace"; @@ -224,6 +247,32 @@ Return New Exception() End Function) Return New Exception() End Function) + {method}(value:= substitute.FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)()), createException:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt (Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt (Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return New Exception() + End Function) + Return New Exception() + End Function) + {method}(createException:= Function(outerCallInfo) + Dim otherSubstitute = NSubstitute.Substitute.[For] (Of IFoo)() + {method}(otherSubstitute.Bar(Arg.Any (Of Integer)()), Function(innerCallInfo) + Dim x = [|outerCallInfo.ArgAt (Of Integer)(2)|] + Dim y = [|outerCallInfo(2)|] + Dim z = outerCallInfo(1) + Dim xx = [|innerCallInfo.ArgAt (Of Integer)(1)|] + Dim yy = [|innerCallInfo(1)|] + Dim zz = innerCallInfo(0) + Return New Exception() + End Function) + Return New Exception() + End Function, value:= substitute.FooBaz(Arg.Any (Of Integer)(), Arg.Any (Of Integer)())) End Sub End Class End Namespace"; @@ -235,7 +284,7 @@ End Class "There is no argument at position 2", "There is no argument at position 1", "There is no argument at position 1" - }; + }.Repeat(3).ToArray(); var diagnostics = textParserResult.Spans.Select((span, idx) => CreateDiagnostic(CallInfoArgumentOutOfRangeDescriptor.OverrideMessage(diagnosticMessages[idx]), span)).ToArray(); await VerifyDiagnostic(textParserResult.Text, diagnostics); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index 2affc70d..3d434f97 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -223,6 +223,7 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() {method}([|substitute.Bar()|], 1) {method}(value:= [|substitute.Bar()|], returnThis:= 1) + {method}(returnThis:= 1, value:= [|substitute.Bar()|]) End Sub End Class End Namespace @@ -274,6 +275,7 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() {method}(substitute.Bar(), 1) {method}(value:= substitute.Bar(), returnThis:= 1) + {method}(returnThis:= 1, value:= substitute.Bar()) End Sub End Class End Namespace @@ -528,6 +530,8 @@ Public Class FooTests Public Sub Test() Dim substitute As Foo = Nothing {method}(substitute.Bar(), 1) + {method}(returnValue:= substitute.Bar(), returnThis:= 1) + {method}(returnThis:= 1, returnValue:= substitute.Bar()) End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index 962d945d..d5953b2d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -34,6 +34,7 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}([|substitute.Bar()|], New Exception()) {method}(value:= [|substitute.Bar()|], ex:= New Exception()) {method}(ex:= New Exception(), value:= [|substitute.Bar()|]) End Sub @@ -123,6 +124,7 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute.Bar(), New Exception()) {method}(value:= substitute.Bar(), ex:= New Exception()) + {method}(ex:= New Exception(), value:= substitute.Bar()) End Sub End Class End Namespace @@ -599,6 +601,8 @@ Public Class FooTests Public Sub Test() Dim substitute As Foo = Nothing {method}(substitute.Bar(), New Exception()) + {method}(returnValue:= substitute.Bar(), ex:= New Exception()) + {method}(ex:= New Exception(), returnValue:= substitute.Bar()) End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs index 0c3461d9..c66ab0bf 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberArgumentMatcherAnalyzerTests/NonSubstitutableMemberArgumentMatcherTests.cs @@ -34,6 +34,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace"; @@ -96,6 +99,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace"; @@ -137,6 +143,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -157,6 +166,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Func(Of {delegateArgType}, Integer))() Dim ___ = substitute({arg}) substitute.When(sub(x) x({arg})) + SubstituteExtensions.When(substitute, sub(x) x({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -204,7 +216,10 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() - substitute.Bar({arg}) + substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -232,6 +247,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace"; @@ -258,6 +276,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -285,7 +306,9 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo(Of Integer))() substitute.Bar(Of Integer)({arg}) - substitute.When(sub(x) x.Bar(Of Integer)({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar(Of Integer)({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar(Of Integer)({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar(Of Integer)({arg}), substitute:= substitute) End Sub End Class End Namespace"; @@ -310,9 +333,11 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() - substitute.When(Function(x) - Dim y = x({arg}) - End Function) + Dim ___ = substitute({arg}) + substitute.When(function(x) x({arg})) + SubstituteExtensions.When(substitute, function(x) x({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= function(x) x({arg})) + SubstituteExtensions.When(substituteCall:= function(x) x({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -344,9 +369,10 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() Dim ___ = substitute({arg}) - substitute.When(Function(x) - Dim y = x({arg}) - End Function) + substitute.When(function(x) x({arg})) + SubstituteExtensions.When(substitute, function(x) x({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= function(x) x({arg})) + SubstituteExtensions.When(substituteCall:= function(x) x({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -385,9 +411,10 @@ Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() Dim ___ = substitute({arg}) - substitute.When(Function(x) - Dim y = x({arg}) - End Function) + substitute.When(function(x) x({arg})) + SubstituteExtensions.When(substitute, function(x) x({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= function(x) x({arg})) + SubstituteExtensions.When(substituteCall:= function(x) x({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -471,6 +498,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.Bar({arg}) substitute.When(sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.Bar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -562,6 +592,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.FooBar({arg}) substitute.When(sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.FooBar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -595,6 +628,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.FooBar({arg}) substitute.When(sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.FooBar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -631,6 +667,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.FooBar({arg}) substitute.When(sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.FooBar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -660,6 +699,9 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.FooBar({arg}) substitute.When(sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute, sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.FooBar({arg})) + SubstituteExtensions.When(substituteCall:= sub(x) x.FooBar({arg}), substitute:= substitute) End Sub End Class End Namespace @@ -704,6 +746,10 @@ Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)() substitute.Bar({arg}, {arg}) substitute.Bar([|{arg}|]) + substitute.When(sub(x) x.Bar([|{arg}|])) + SubstituteExtensions.When(substitute, sub(x) x.Bar([|{arg}|])) + SubstituteExtensions.When(substitute:= substitute, substituteCall:= sub(x) x.Bar([|{arg}|])) + SubstituteExtensions.When(substituteCall:= sub(x) x.Bar([|{arg}|]), substitute:= substitute) End Sub End Class End Namespace @@ -819,12 +865,26 @@ End Namespace } [CombinatoryData( - "Received(Quantity.None())", - "Received()", - "ReceivedWithAnyArgs(Quantity.None())", - "ReceivedWithAnyArgs()", - "DidNotReceive()", - "DidNotReceiveWithAnyArgs()")] + "substitute.Received(Quantity.None())", + "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "substitute.Received()", + "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute:= substitute)", + "substitute.ReceivedWithAnyArgs(Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity:= Quantity.None(), substitute:= substitute)", + "substitute.ReceivedWithAnyArgs()", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute)", + "substitute.DidNotReceive()", + "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute)", + "substitute.DidNotReceiveWithAnyArgs()", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute)")] public override async Task ReportsDiagnostics_WhenAssigningInvalidArgMatchersToMemberPrecededByWithAnyArgsLikeMethod(string receivedMethod, string arg) { var source = $@"Imports System @@ -840,8 +900,8 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() - substitute.{receivedMethod}.Foo = {arg} - substitute.{receivedMethod}(1) = {arg} + {receivedMethod}.Foo = {arg} + {receivedMethod}(1) = {arg} End Sub End Class End Namespace @@ -875,7 +935,19 @@ Public Sub Test() substitute.{whenMethod}(Function(x) Dim y = x.Bar = {arg} End Function) + SubstituteExtensions.{whenMethod}(substitute, Function(x) + Dim y = x.Bar = {arg} + End Function) + SubstituteExtensions.{whenMethod}(substitute:= substitute, substituteCall:= Function(x) + Dim y = x.Bar = {arg} + End Function) + SubstituteExtensions.{whenMethod}(substituteCall:= Function(x) + Dim y = x.Bar = {arg} + End Function, substitute:= substitute) substitute.{whenMethod}(sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substitute, sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substitute:= substitute, substituteCall:= sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substituteCall:= sub(x) x(1) = {arg}, substitute:= substitute) End Sub End Class End Namespace"; @@ -898,10 +970,19 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.For(Of Foo) - substitute.{whenMethod}(Function(x) + SubstituteExtensions.{whenMethod}(substitute, Function(x) Dim y = x.Bar = {arg} End Function) + SubstituteExtensions.{whenMethod}(substitute:= substitute, substituteCall:= Function(x) + Dim y = x.Bar = {arg} + End Function) + SubstituteExtensions.{whenMethod}(substituteCall:= Function(x) + Dim y = x.Bar = {arg} + End Function, substitute:= substitute) substitute.{whenMethod}(sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substitute, sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substitute:= substitute, substituteCall:= sub(x) x(1) = {arg}) + SubstituteExtensions.{whenMethod}(substituteCall:= sub(x) x(1) = {arg}, substitute:= substitute) End Sub End Class End Namespace"; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs index a5c06308..26d5c5f1 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -187,8 +187,9 @@ Public Class FooTests Public Sub Test() Dim i As Integer = 1 Dim substitute = NSubstitute.Substitute.[For](Of Foo)() - {method}(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + {method}(substitute, {whenAction}).[Do](Sub(callInfo) i = i +1) {method}(substitute:= substitute, substituteCall:= {whenAction}).[Do](Sub(callInfo) i = i +1) + {method}(substituteCall:= {whenAction}, substitute:= substitute).[Do](Sub(callInfo) i = i +1) End Sub End Class End Namespace @@ -210,6 +211,7 @@ Public Class FooTests Public Sub Test() Dim i As Integer = 1 Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, {whenAction}).[Do](Sub(callInfo) i = i +1) {method}(substitute:= substitute, substituteCall:= {whenAction}).[Do](Sub(callInfo) i = i +1) {method}(substituteCall:= {whenAction}, substitute:= substitute).[Do](Sub(callInfo) i = i +1) End Sub @@ -231,7 +233,7 @@ Public Sub Test() Dim i As Integer = 1 Dim substitute = NSubstitute.Substitute.[For](Of Foo)() {method}(substitute, {whenAction}).[Do](Sub(callInfo) i = i + 1) - {method}(substitute: =substitute, substituteCall:= {whenAction}).[Do](Sub(callInfo) i = i + 1) + {method}(substitute:= substitute, substituteCall:= {whenAction}).[Do](Sub(callInfo) i = i + 1) {method}(substituteCall:= {whenAction}, substitute:= substitute).[Do](Sub(callInfo) i = i + 1) End Sub End Class @@ -263,6 +265,7 @@ Public Sub Test() End Sub End Class End Namespace"; + await VerifyNoDiagnostic(source); } diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs index cbf9c5fe..53e3d2a7 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs @@ -36,7 +36,7 @@ End Interface Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of IFoo)(1)|] - Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of IFoo)(New Integer() { 1 })|] + Dim anotherSubstitute = [|NSubstitute.Substitute.[For](Of IFoo)(New Integer() { 1 })|] End Sub End Class End Namespace"; @@ -540,6 +540,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For](Of Foo)(1, 2, 3) + Dim otherSubstitute = NSubstitute.Substitute.[For](Of Foo)(New Object() { 1, 2, New Integer() { 3 } }) End Sub End Class End Namespace @@ -560,6 +561,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For](Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](Of Foo)(New Integer() { 1 })|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs index d5d50702..a7cc53f0 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForAsNonGenericMethodTests.cs @@ -643,6 +643,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, New Object() {1, 2, 3}) + Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3}) + Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -663,6 +665,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[For]({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|NSubstitute.Substitute.[For](constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs index 5c9a84d1..2ff7937d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs @@ -384,6 +384,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[ForPartsOf](Of Foo)(1, 2, 3) + Dim otherSubstitute = NSubstitute.Substitute.[ForPartsOf](Of Foo)(New Object() { 1, 2, New Integer() { 3 } }) End Sub End Class End Namespace @@ -404,6 +405,7 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|NSubstitute.Substitute.[ForPartsOf](Of Foo)(1)|] + Dim otherSubstitute = [|NSubstitute.Substitute.[ForPartsOf](Of Foo)(New Integer() { 1 })|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs index 1c9ebcbd..f3a76505 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreateMethodTests.cs @@ -586,6 +586,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1}) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -607,6 +609,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1, 2, 3}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3}) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -628,6 +632,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs index 26089d06..923ee2ac 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/SubstituteAnalyzerTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -183,6 +183,7 @@ Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(Foo)}, Nothing) Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(Foo)}, constructorArguments:= Nothing) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(Foo)}) End Sub End Class End Namespace @@ -407,7 +408,10 @@ Imports NSubstitute.Core Namespace MyNamespace Public Class FooTests Public Function Foo(Of T As Class)() As T - Return CType(SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(T)}, Nothing), T) + Dim substitute = CType(SubstitutionContext.Current.SubstituteFactory.CreatePartial(New Type() {GetType(T)}, Nothing), T) + Dim otherSubstitute = CType(SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= New Type() {GetType(T)}, constructorArguments:= Nothing), T) + Dim yetAnotherSubstitute = CType(SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= New Type() {GetType(T)}), T) + Return substitute End Function End Class End Namespace @@ -429,6 +433,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, New Object() {1}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1}) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -450,6 +456,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, New Object() {1, 2, 3}) + Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1, 2, 3}) + Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1, 2, 3}, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -471,6 +479,8 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, New Object() {1})|] + Dim otherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= New Object() {1})|] + Dim yetAnotherSubstitute = [|SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= New Object() {1}, typesToProxy:= {GetType(Foo)})|] End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index f7625185..32d38598 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -5,23 +5,42 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.Unuse [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(requiredQuantity:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute:= substitute)", "SubstituteExtensions.Received(Of Foo)(substitute)", + "SubstituteExtensions.Received(Of Foo)(substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(requiredQuantity:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute)", "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute)", "SubstituteExtensions.DidNotReceive(Of Foo)(substitute)", + "SubstituteExtensions.DidNotReceive(Of Foo)(substitute:= substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute:= substitute)")] public class ReceivedAsOrdinaryMethodTests : UnusedReceivedDiagnosticVerifier { public override async Task ReportDiagnostics_WhenUsedWithoutMemberCall(string method) { var plainMethodName = method.Replace("(Of Foo)", string.Empty) .Replace("(substitute, Quantity.None())", string.Empty) + .Replace("(substitute:= substitute, requiredQuantity:= Quantity.None())", string.Empty) + .Replace("(requiredQuantity:= Quantity.None(), substitute:= substitute)", string.Empty) + .Replace("(substitute:= substitute)", string.Empty) .Replace("(substitute)", string.Empty); var planMethodNameWithoutNamespace = plainMethodName.Replace("SubstituteExtensions.", string.Empty) @@ -117,17 +136,33 @@ End Namespace [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(requiredQuantity:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.Received(Of Func(Of Integer))(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Func(Of Integer))(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.Received(Of Func(Of Integer))(requiredQuantity:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.Received(substitute)", + "SubstituteExtensions.Received(substitute:= substitute)", "SubstituteExtensions.Received(Of Func(Of Integer))(substitute)", + "SubstituteExtensions.Received(Of Func(Of Integer))(substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(requiredQuantity:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(Of Func(Of Integer))(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Func(Of Integer))(substitute:= substitute, requiredQuantity:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Func(Of Integer))(requiredQuantity:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(Of Func(Of Integer))(substitute)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Func(Of Integer))(substitute:= substitute)", "SubstituteExtensions.DidNotReceive(substitute)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute)", "SubstituteExtensions.DidNotReceive(Of Func(Of Integer))(substitute)", + "SubstituteExtensions.DidNotReceive(Of Func(Of Integer))(substitute:= substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Func(Of Integer))(substitute)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Func(Of Integer))(substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Func(Of Integer))(substitute:= substitute)")] public override async Task ReportNoDiagnostics_WhenUsedWithInvokingDelegate(string method) { var source = $@"Imports NSubstitute From 154a51aa1a7cd707b0bca25b2d72c83d94afd53b Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 9 Sep 2022 03:02:51 +0200 Subject: [PATCH 28/35] GH-153 - ConflictingArgumentAssignmentsAnalyzer fixes --- .../AbstractConflictingArgumentAssignmentsAnalyzer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index c0aa00a9..9a9bb586 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -57,14 +57,14 @@ private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) var previousCallIndexers = FindCallInfoIndexers(substituteOperation); - var immutableHashSet = previousCallIndexers + var previousCallIndexerPositions = previousCallIndexers .Select(indexerPropertyReferenceOperation => indexerPropertyReferenceOperation.GetIndexerPosition()) .ToImmutableHashSet(); foreach (var indexerExpressionSyntax in andDoesIndexers) { var position = indexerExpressionSyntax.GetIndexerPosition(); - if (position.HasValue && immutableHashSet.Contains(position.Value)) + if (position.HasValue && previousCallIndexerPositions.Contains(position.Value)) { syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptorsProvider.ConflictingArgumentAssignments, @@ -81,7 +81,7 @@ private IEnumerable FindCallInfoIndexers(IInvocationOperation invoca foreach (var propertyReference in _callInfoFinder .GetCallInfoContext(argumentOperation).IndexerAccessesOperations) { - if (propertyReference.Parent is ISimpleAssignmentOperation) + if (propertyReference is IPropertyReferenceOperation && propertyReference.Parent is ISimpleAssignmentOperation) { yield return propertyReference; } From f94b82c52b208bb3b84503522e5b42dc5c3b69bc Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 9 Sep 2022 16:02:59 +0200 Subject: [PATCH 29/35] GH-153 - null checks for SyncOverAsyncThrowsCodeFixProvider --- ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 2e3e1df7..25c83925 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -38,25 +38,29 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocation) + if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocationExpression) { return; } var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - var methodSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(invocation).Symbol; + if (semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) + { + return; + } + var supportsThrowsAsync = SupportsThrowsAsync(semanticModel.Compilation); - if (!supportsThrowsAsync && methodSymbol.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel.Compilation))) + if (!supportsThrowsAsync && invocationOperation.TargetMethod.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel.Compilation))) { return; } - var replacementMethod = GetReplacementMethodName(methodSymbol, useModernSyntax: supportsThrowsAsync); + var replacementMethod = GetReplacementMethodName(invocationOperation, useModernSyntax: supportsThrowsAsync); var codeAction = CodeAction.Create( $"Replace with {replacementMethod}", - ct => CreateChangedDocument(context, semanticModel, invocation, methodSymbol, supportsThrowsAsync, ct), + ct => CreateChangedDocument(context, semanticModel, invocationOperation, supportsThrowsAsync, ct), nameof(AbstractSyncOverAsyncThrowsCodeFixProvider)); context.RegisterCodeFix(codeAction, diagnostic); @@ -67,13 +71,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) private async Task CreateChangedDocument( CodeFixContext context, SemanticModel semanticModel, - SyntaxNode currentInvocationExpression, - IMethodSymbol invocationSymbol, + IInvocationOperation invocationOperation, bool useModernSyntax, CancellationToken cancellationToken) { var documentEditor = await DocumentEditor.CreateAsync(context.Document, cancellationToken); - var invocationOperation = (IInvocationOperation)semanticModel.GetOperation(currentInvocationExpression); + var invocationSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(invocationOperation.Syntax).Symbol; var updatedInvocationExpression = useModernSyntax ? await CreateThrowsAsyncInvocationExpression( @@ -85,7 +88,7 @@ private async Task CreateChangedDocument( invocationSymbol, context); - documentEditor.ReplaceNode(currentInvocationExpression, updatedInvocationExpression); + documentEditor.ReplaceNode(invocationOperation.Syntax, updatedInvocationExpression); return documentEditor.GetChangedDocument(); } @@ -209,16 +212,18 @@ private static bool SupportsThrowsAsync(Compilation compilation) exceptionExtensionsTypeSymbol.GetMembers(MetadataNames.NSubstituteThrowsAsyncMethod).IsEmpty == false; } - private static string GetReplacementMethodName(IMethodSymbol methodSymbol, bool useModernSyntax) + private static string GetReplacementMethodName(IInvocationOperation invocationOperation, bool useModernSyntax) { + var isThrowsSyncMethod = invocationOperation.TargetMethod.IsThrowsSyncMethod(); + if (useModernSyntax) { - return methodSymbol.IsThrowsSyncMethod() + return isThrowsSyncMethod ? MetadataNames.NSubstituteThrowsAsyncMethod : MetadataNames.NSubstituteThrowsAsyncForAnyArgsMethod; } - return methodSymbol.IsThrowsSyncMethod() + return isThrowsSyncMethod ? MetadataNames.NSubstituteReturnsMethod : MetadataNames.NSubstituteReturnsForAnyArgsMethod; } From a3704ba71b247e8d39533d83094bb15fd556f8d5 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 9 Sep 2022 16:15:21 +0200 Subject: [PATCH 30/35] GH-153 - clean-up --- .../AbstractDiagnosticAnalyzersBenchmarks.cs | 12 +++--- .../Shared/AbstractSolutionLoader.cs | 34 ++++++++--------- .../ConflictingArgumentAssignmentsAnalyzer.cs | 1 - ...stitutableMemberReceivedInOrderAnalyzer.cs | 5 --- .../AbstractReEntrantSetupCodeFixProvider.cs | 14 +------ ...actAsyncReceivedInOrderCallbackAnalyzer.cs | 2 - ...tConflictingArgumentAssignmentsAnalyzer.cs | 6 +-- .../AbstractDiagnosticAnalyzer.cs | 3 +- .../AbstractReEntrantSetupAnalyzer.cs | 13 +------ .../DiagnosticAnalyzers/CallInfoFinder.cs | 3 +- .../ISubstitutionNodeFinder.cs | 1 - .../Extensions/IOperationExtensions.cs | 10 ++++- .../Extensions/ISymbolExtensions.cs | 5 --- ... => OperationAnalysisContextExtensions.cs} | 24 ++---------- .../Extensions/SyntaxNodeExtensions.cs | 36 ------------------ .../Extensions/TypeInfoExtensions.cs | 6 --- .../TinyJson/JsonParser.cs | 6 +-- ...stituteForInternalMemberCodeFixProvider.cs | 1 - .../ConflictingArgumentAssignmentsAnalyzer.cs | 1 - ...alSetupSpecificationCodeFixActionsTests.cs | 20 +++++----- ...bstituteFactoryCreatePartialMethodTests.cs | 1 - ...uteForInternalMemberCodeFixActionsTests.cs | 20 +++++----- .../SuppressDiagnosticSettingsVerifier.cs | 38 +++++++++---------- .../CodeRefactoringProviderActionsVerifier.cs | 20 +++++----- .../CodeRefactoringProviderVerifier.cs | 18 ++++----- .../DocumentationTests/DocumentationTests.cs | 10 ++--- ...alSetupSpecificationCodeFixActionsTests.cs | 20 +++++----- ...uteForInternalMemberCodeFixActionsTests.cs | 20 +++++----- .../ThrowsAsExtensionMethodTests.cs | 1 - .../ThrowsAsOrdinaryMethodTests.cs | 1 - .../ReturnsAsOrdinaryMethodTests.cs | 1 - 31 files changed, 118 insertions(+), 235 deletions(-) rename src/NSubstitute.Analyzers.Shared/Extensions/{SyntaxNodeAnalysisContextExtensions.cs => OperationAnalysisContextExtensions.cs} (72%) delete mode 100644 src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs index e8e092b8..936c635c 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractDiagnosticAnalyzersBenchmarks.cs @@ -213,14 +213,12 @@ private Solution CreateSolution() foreach (var projectId in projectGraph.GetTopologicallySortedProjects()) { var projectCompilation = solution.GetProject(projectId).GetCompilationAsync().Result; - using (var stream = new MemoryStream()) + using var stream = new MemoryStream(); + var result = projectCompilation.Emit(stream); + if (result.Success == false) { - var result = projectCompilation.Emit(stream); - if (result.Success == false) - { - throw new InvalidOperationException( - $"Compilation for benchmark source failed {Environment.NewLine} {string.Join(Environment.NewLine, result.Diagnostics.Select(diag => diag.ToString()))}"); - } + throw new InvalidOperationException( + $"Compilation for benchmark source failed {Environment.NewLine} {string.Join(Environment.NewLine, result.Diagnostics.Select(diag => diag.ToString()))}"); } } diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractSolutionLoader.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractSolutionLoader.cs index 40126e7a..f881f5a9 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractSolutionLoader.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AbstractSolutionLoader.cs @@ -19,29 +19,27 @@ public abstract class AbstractSolutionLoader public Solution CreateSolution(string projectDirectory, MetadataReference[] metadataReferences) { var projectName = Path.GetFileName(projectDirectory); - using (var adhocWorkspace = new AdhocWorkspace()) - { - var projectId = ProjectId.CreateNewId(); - var solution = adhocWorkspace - .CurrentSolution - .AddProject(projectId, projectName, projectName, Language); + using var adhocWorkspace = new AdhocWorkspace(); + var projectId = ProjectId.CreateNewId(); + var solution = adhocWorkspace + .CurrentSolution + .AddProject(projectId, projectName, projectName, Language); - foreach (var fileInfo in GetFiles(projectDirectory).Where(fileInfo => fileInfo.Extension != ProjectFileExtension)) + foreach (var fileInfo in GetFiles(projectDirectory).Where(fileInfo => fileInfo.Extension != ProjectFileExtension)) + { + if (fileInfo.Name == _analyzerSettingsFileName) { - if (fileInfo.Name == _analyzerSettingsFileName) - { - solution = solution.AddAdditionalDocument(DocumentId.CreateNewId(projectId), fileInfo.Name, File.ReadAllText(fileInfo.FullName)); - } - - if (fileInfo.Extension == DocumentFileExtension) - { - solution = solution.AddDocument(DocumentId.CreateNewId(projectId), fileInfo.Name, File.ReadAllText(fileInfo.FullName)); - } + solution = solution.AddAdditionalDocument(DocumentId.CreateNewId(projectId), fileInfo.Name, File.ReadAllText(fileInfo.FullName)); } - return solution.AddMetadataReferences(projectId, metadataReferences) - .WithProjectCompilationOptions(projectId, GetCompilationOptions(projectName)); + if (fileInfo.Extension == DocumentFileExtension) + { + solution = solution.AddDocument(DocumentId.CreateNewId(projectId), fileInfo.Name, File.ReadAllText(fileInfo.FullName)); + } } + + return solution.AddMetadataReferences(projectId, metadataReferences) + .WithProjectCompilationOptions(projectId, GetCompilationOptions(projectName)); } protected abstract CompilationOptions GetCompilationOptions(string rootNamespace); diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index 5f03b3db..78f792fb 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -1,5 +1,4 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs index 16c878b6..0f82de9a 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -1,6 +1,4 @@ -using System.Collections.Immutable; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; @@ -9,9 +7,6 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed class NonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableMemberReceivedInOrderAnalyzer { - private static ImmutableArray IgnoredPaths { get; } = - ImmutableArray.Create((int)SyntaxKind.Argument, (int)SyntaxKind.VariableDeclarator, (int)SyntaxKind.AddAssignmentExpression); - public NonSubstitutableMemberReceivedInOrderAnalyzer() : base(SubstitutionNodeFinder.Instance, NonSubstitutableMemberAnalysis.Instance, NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance) { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs index 62dbcbbd..74b37789 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs @@ -74,16 +74,6 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) // generate array expression per language on our own protected abstract SyntaxNode CreateArrayCreationExpression(SyntaxNode typeSyntax, IEnumerable elements); - private IEnumerable GetArrayOperationValues(IArgumentOperation argumentOperation) - { - return argumentOperation.Value switch - { - IArrayCreationOperation arrayCreationOperation => arrayCreationOperation.Initializer.ElementValues, - IArrayInitializerOperation arrayInitializerOperation => arrayInitializerOperation.ElementValues, - _ => null - }; - } - private async Task CreateChangedDocument( CodeFixContext context, SemanticModel semanticModel, @@ -141,7 +131,7 @@ private TArgumentSyntax CreateUpdatedParamsArgument( { var lambdaType = ConstructCallInfoLambdaType(methodSymbol, semanticModel.Compilation); var lambdaTypeSyntax = syntaxGenerator.TypeExpression(lambdaType); - var arrayElements = GetArrayOperationValues(argumentOperation) + var arrayElements = argumentOperation.Value.GetArrayElementValues() .Select(operation => CreateLambdaExpression(syntaxGenerator, operation.Syntax)); var arrayCreationExpression = CreateArrayCreationExpression(lambdaTypeSyntax, arrayElements); @@ -180,7 +170,7 @@ private bool IsFixSupported(IInvocationOperation invocationOperation) return false; } - var arrayValues = GetArrayOperationValues(argumentOperation); + var arrayValues = argumentOperation.Value.GetArrayElementValues(); return IsArrayParamsArgument(argumentOperation) == false || (arrayValues != null && arrayValues.All(exp => exp is not IAwaitOperation)); }); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs index 8c15a4b5..9d947a63 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index 9a9bb586..8075370d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -61,14 +61,14 @@ private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) .Select(indexerPropertyReferenceOperation => indexerPropertyReferenceOperation.GetIndexerPosition()) .ToImmutableHashSet(); - foreach (var indexerExpressionSyntax in andDoesIndexers) + foreach (var indexerOperation in andDoesIndexers) { - var position = indexerExpressionSyntax.GetIndexerPosition(); + var position = indexerOperation.GetIndexerPosition(); if (position.HasValue && previousCallIndexerPositions.Contains(position.Value)) { syntaxNodeContext.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptorsProvider.ConflictingArgumentAssignments, - indexerExpressionSyntax.Syntax.GetLocation())); + indexerOperation.Syntax.GetLocation())); } } } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs index 5c646601..05f687bf 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractDiagnosticAnalyzer.cs @@ -13,8 +13,7 @@ protected AbstractDiagnosticAnalyzer(IDiagnosticDescriptorsProvider diagnosticDe public sealed override void Initialize(AnalysisContext context) { - // TODO restore - // context.EnableConcurrentExecution(); + context.EnableConcurrentExecution(); InitializeAnalyzer(context); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index b59a7bd7..a8e01ef4 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; @@ -68,7 +67,7 @@ private void AnalyzeParamsArgument( IArgumentOperation argumentOperation, IInvocationOperation invocationOperation) { - var initializerOperations = GetOperationsFromArrayInitializer(argumentOperation); + var initializerOperations = argumentOperation.Value.GetArrayElementValues(); if (initializerOperations != null) { @@ -84,16 +83,6 @@ private void AnalyzeParamsArgument( AnalyzeExpression(context, argumentOperation.Value, invocationOperation); } - private IEnumerable GetOperationsFromArrayInitializer(IArgumentOperation argumentOperation) - { - return argumentOperation.Value switch - { - IArrayCreationOperation arrayCreationOperation => arrayCreationOperation.Initializer.ElementValues, - IArrayInitializerOperation arrayInitializerOperation => arrayInitializerOperation.ElementValues, - _ => null - }; - } - private void AnalyzeExpression( OperationAnalysisContext context, IOperation operation, diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs index 655fd824..72e7eeb6 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs @@ -99,8 +99,7 @@ private static IEnumerable GetCallInfoOperations(IArgumentOperation yield break; } - var initializerElementValues = - (argumentOperation.Value as IArrayCreationOperation)?.Initializer.ElementValues; + var initializerElementValues = argumentOperation.Value.GetArrayElementValues(); foreach (var operation in initializerElementValues ?? Enumerable.Empty()) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs index 0fde77fe..84f2f456 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ISubstitutionNodeFinder.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 15bc630d..1c32ba01 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; @@ -126,6 +125,15 @@ public static ISymbol ExtractSymbol(this IOperation operation) return symbol; } + public static IEnumerable GetArrayElementValues(this IOperation operation) + { + return operation switch + { + IArrayCreationOperation arrayCreationOperation => arrayCreationOperation.Initializer.ElementValues, + _ => null + }; + } + private static bool IsImplicitlyProvidedArrayWithoutValues(IArgumentOperation arg) { return arg.IsImplicit && diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/ISymbolExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/ISymbolExtensions.cs index 870ff1a6..6dc451e2 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/ISymbolExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/ISymbolExtensions.cs @@ -36,9 +36,4 @@ public static string ToMinimalSymbolString(this ISymbol symbol, SemanticModel se { return symbol.ToMinimalDisplayString(semanticModel, 0, SymbolDisplayFormat.CSharpErrorMessageFormat); } - - public static bool IsLocal(this ISymbol symbol) - { - return symbol != null && symbol.Kind == SymbolKind.Local; - } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/OperationAnalysisContextExtensions.cs similarity index 72% rename from src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs rename to src/NSubstitute.Analyzers.Shared/Extensions/OperationAnalysisContextExtensions.cs index 7fbfbb8a..c797f125 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeAnalysisContextExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/OperationAnalysisContextExtensions.cs @@ -8,26 +8,8 @@ namespace NSubstitute.Analyzers.Shared.Extensions; -internal static class SyntaxNodeAnalysisContextExtensions +internal static class OperationAnalysisContextExtensions { - internal static AnalyzersSettings GetSettings(this SyntaxNodeAnalysisContext context, CancellationToken cancellationToken) - { - return context.Options.GetSettings(cancellationToken); - } - - internal static void TryReportDiagnostic( - this SyntaxNodeAnalysisContext syntaxNodeContext, - Diagnostic diagnostic, - ISymbol symbol) - { - if (IsSuppressed(syntaxNodeContext.GetSettings(CancellationToken.None), syntaxNodeContext.Compilation, symbol, diagnostic.Id)) - { - return; - } - - syntaxNodeContext.ReportDiagnostic(diagnostic); - } - internal static void TryReportDiagnostic( this OperationAnalysisContext syntaxNodeContext, Diagnostic diagnostic, @@ -79,9 +61,9 @@ private static IEnumerable GetPossibleSymbols(ISymbol symbol) } } - if (symbol.ContainingType is INamedTypeSymbol namedTypeSymbol) + if (symbol.ContainingType != null) { - yield return namedTypeSymbol.ConstructedFrom; + yield return symbol.ContainingType.ConstructedFrom; } if (symbol is IPropertySymbol propertySymbol) diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs deleted file mode 100644 index 58c52cbe..00000000 --- a/src/NSubstitute.Analyzers.Shared/Extensions/SyntaxNodeExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using Microsoft.CodeAnalysis; - -namespace NSubstitute.Analyzers.Shared.Extensions; - -internal static class SyntaxNodeExtensions -{ - public static SyntaxNode GetParentNode(this SyntaxNode syntaxNode, IEnumerable parentNodeHierarchyKinds) - { - return GetNodeInHierarchy(syntaxNode.DescendantNodes(), parentNodeHierarchyKinds); - } - - private static SyntaxNode GetNodeInHierarchy(IEnumerable nodes, IEnumerable hierarchyKindPath) - { - using (var descendantNodesEnumerator = nodes.GetEnumerator()) - { - using (var hierarchyKindEnumerator = hierarchyKindPath.GetEnumerator()) - { - while (hierarchyKindEnumerator.MoveNext() && descendantNodesEnumerator.MoveNext()) - { - if (descendantNodesEnumerator.Current.RawKind != hierarchyKindEnumerator.Current) - { - return null; - } - } - - if (hierarchyKindEnumerator.MoveNext() == false) - { - return descendantNodesEnumerator.Current; - } - } - } - - return null; - } -} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs index 06e3b7d9..83d8f349 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/TypeInfoExtensions.cs @@ -6,12 +6,6 @@ namespace NSubstitute.Analyzers.Shared.Extensions; internal static class TypeInfoExtensions { - public static bool IsCallInfoDelegate(this TypeInfo typeInfo, Compilation compilation) - { - var typeSymbol = typeInfo.Type ?? typeInfo.ConvertedType; - return typeSymbol.IsCallInfoDelegate(compilation); - } - public static bool IsCallInfoDelegate(this ITypeSymbol typeSymbol, Compilation compilation) { var isCalledViaDelegate = typeSymbol != null && diff --git a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs index f0155f46..41b09a35 100644 --- a/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs +++ b/src/NSubstitute.Analyzers.Shared/TinyJson/JsonParser.cs @@ -31,10 +31,8 @@ private enum Token public static object ParseValue(string jsonString) { - using (var parser = new JsonParser(jsonString)) - { - return parser.ParseValue(); - } + using var parser = new JsonParser(jsonString); + return parser.ParseValue(); } internal JsonParser(string jsonString) diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index af372ac7..13456f8b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -3,7 +3,6 @@ using Microsoft.CodeAnalysis.VisualBasic.Syntax; using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; using NSubstitute.Analyzers.VisualBasic.Refactorings; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs index bfdd4520..37bdf300 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/ConflictingArgumentAssignmentsAnalyzer.cs @@ -1,6 +1,5 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.VisualBasic; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs index 877e95c1..933b4289 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs @@ -97,18 +97,16 @@ internal virtual int Bar() var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); - using (var ms = new MemoryStream()) - { - var result = compilation.Emit(ms); - - if (result.Success == false) - { - var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); - throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); - } + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); - ms.Seek(0, SeekOrigin.Begin); - return MetadataReference.CreateFromStream(ms); + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs index a7512798..22a8a375 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Xunit; namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForInternalMemberCodeFixProviderTests; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs index cf32490a..43a55716 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs @@ -114,18 +114,16 @@ internal class InternalFoo var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); - using (var ms = new MemoryStream()) - { - var result = compilation.Emit(ms); - - if (result.Success == false) - { - var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); - throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); - } + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); - ms.Seek(0, SeekOrigin.Begin); - return MetadataReference.CreateFromStream(ms); + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs index 6452edd7..9f2a5abc 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/SuppressDiagnosticSettingsVerifier.cs @@ -49,32 +49,30 @@ private async Task VerifySuppressionSettings(Document document, AnalyzersSetting private async Task ApplySettingsSuppressionFix(string source, int? codeFixIndex = null) { - using (var workspace = new AdhocWorkspace()) - { - var project = AddProject(workspace.CurrentSolution, source); + using var workspace = new AdhocWorkspace(); + var project = AddProject(workspace.CurrentSolution, source); - var document = project.Documents.Single(); - var compilation = await document.Project.GetCompilationAsync(); - var compilerDiagnostics = compilation.GetDiagnostics(); + var document = project.Documents.Single(); + var compilation = await document.Project.GetCompilationAsync(); + var compilerDiagnostics = compilation.GetDiagnostics(); - VerifyNoCompilerDiagnosticErrors(compilerDiagnostics); + VerifyNoCompilerDiagnosticErrors(compilerDiagnostics); - var analyzerDiagnostics = await compilation.GetSortedAnalyzerDiagnostics( - DiagnosticAnalyzer, - project.AnalyzerOptions); + var analyzerDiagnostics = await compilation.GetSortedAnalyzerDiagnostics( + DiagnosticAnalyzer, + project.AnalyzerOptions); - var actions = new List(); - var context = new CodeFixContext( - document, - analyzerDiagnostics.Single(), - (a, d) => actions.Add(a), - CancellationToken.None); + var actions = new List(); + var context = new CodeFixContext( + document, + analyzerDiagnostics.Single(), + (a, d) => actions.Add(a), + CancellationToken.None); - await CodeFixProvider.RegisterCodeFixesAsync(context); - var action = actions[codeFixIndex ?? 0]; + await CodeFixProvider.RegisterCodeFixesAsync(context); + var action = actions[codeFixIndex ?? 0]; - return await document.ApplyCodeAction(action); - } + return await document.ApplyCodeAction(action); } private static AnalyzersSettings GetExpectedSettings(AnalyzersSettings originalSettings, string target, string diagnosticRuleId) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderActionsVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderActionsVerifier.cs index ed25e378..5ae940a1 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderActionsVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderActionsVerifier.cs @@ -30,21 +30,19 @@ protected async Task VerifyCodeActions(string source, params string[] expectedCo throw new ArgumentException("Refactoring spans should not be empty", nameof(source)); } - using (var workspace = new AdhocWorkspace()) - { - var project = AddProject(workspace.CurrentSolution, parserResult.Text); - var document = project.Documents.Single(); + using var workspace = new AdhocWorkspace(); + var project = AddProject(workspace.CurrentSolution, parserResult.Text); + var document = project.Documents.Single(); - var codeActionTasks = spans - .Select(span => RegisterCodeRefactoringActions(document, span)).ToList(); + var codeActionTasks = spans + .Select(span => RegisterCodeRefactoringActions(document, span)).ToList(); - await Task.WhenAll(codeActionTasks); + await Task.WhenAll(codeActionTasks); - var codeActions = codeActionTasks.SelectMany(task => task.Result).ToList(); + var codeActions = codeActionTasks.SelectMany(task => task.Result).ToList(); - codeActions.Should().NotBeNull(); - codeActions.Select(action => action.Title).Should().BeEquivalentTo(expectedCodeActionTitles ?? Array.Empty()); - } + codeActions.Should().NotBeNull(); + codeActions.Select(action => action.Title).Should().BeEquivalentTo(expectedCodeActionTitles ?? Array.Empty()); } private async Task> RegisterCodeRefactoringActions(Document document, TextSpan span) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderVerifier.cs index bd427315..465aca3c 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeRefactoringProviders/CodeRefactoringProviderVerifier.cs @@ -30,18 +30,16 @@ protected async Task VerifyRefactoring(string oldSource, string newSource, int? throw new ArgumentException("Refactoring spans should not be empty", nameof(oldSource)); } - using (var workspace = new AdhocWorkspace()) - { - var project = AddProject(workspace.CurrentSolution, parserResult.Text); - var document = project.Documents.Single(); + using var workspace = new AdhocWorkspace(); + var project = AddProject(workspace.CurrentSolution, parserResult.Text); + var document = project.Documents.Single(); - var actions = await RegisterCodeRefactoringActions(document, spans.Single().Span); + var actions = await RegisterCodeRefactoringActions(document, spans.Single().Span); - var codeAction = actions[refactoringIndex ?? 0]; - var updatedDocument = await document.ApplyCodeAction(codeAction); - var updatedSource = await updatedDocument.ToFullString(); - updatedSource.Should().Be(newSource); - } + var codeAction = actions[refactoringIndex ?? 0]; + var updatedDocument = await document.ApplyCodeAction(codeAction); + var updatedSource = await updatedDocument.ToFullString(); + updatedSource.Should().Be(newSource); } private async Task> RegisterCodeRefactoringActions(Document document, TextSpan span) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs index 053da12f..5641ccb8 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/DocumentationTests/DocumentationTests.cs @@ -199,12 +199,10 @@ private void AssertRuleSummaryCauseCell(TableCell cell, DiagnosticDescriptor des private static string GetBlockText(LeafBlock heading) { - using (var stringWriter = new StringWriter()) - { - var renderer = new NormalizeRenderer(stringWriter); - renderer.Write(heading.Inline); - return stringWriter.ToString(); - } + using var stringWriter = new StringWriter(); + var renderer = new NormalizeRenderer(stringWriter); + renderer.Write(heading.Inline); + return stringWriter.ToString(); } private class HeadingContainer diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs index 3a7257a9..97284333 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs @@ -89,18 +89,16 @@ End Namespace var compilationOptions = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var compilation = VisualBasicCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); - using (var ms = new MemoryStream()) - { - var result = compilation.Emit(ms); - - if (result.Success == false) - { - var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); - throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); - } + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); - ms.Seek(0, SeekOrigin.Begin); - return MetadataReference.CreateFromStream(ms); + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs index c7ccd855..6deb53fd 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixActionsTests.cs @@ -106,18 +106,16 @@ End Namespace var compilationOptions = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var compilation = VisualBasicCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); - using (var ms = new MemoryStream()) - { - var result = compilation.Emit(ms); - - if (result.Success == false) - { - var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); - throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); - } + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); - ms.Seek(0, SeekOrigin.Begin); - return MetadataReference.CreateFromStream(ms); + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); } } \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsExtensionMethodTests.cs index eb6ae576..04de7ace 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsExtensionMethodTests.cs @@ -4,7 +4,6 @@ using NSubstitute.Analyzers.Shared.Settings; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; -using Xunit; namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonSubstitutableMemberAnalyzerTests; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index d5953b2d..6a92d018 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Threading.Tasks; -using MoreLinq.Extensions; using NSubstitute.Analyzers.Shared; using NSubstitute.Analyzers.Shared.Settings; using NSubstitute.Analyzers.Tests.Shared.Extensibility; diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index e345e1af..e7f8f76a 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReEntrantReturnsSetupAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Threading.Tasks; -using MoreLinq.Extensions; using NSubstitute.Analyzers.Tests.Shared.Extensibility; using NSubstitute.Analyzers.Tests.Shared.Extensions; From a89afb53ca520d5be57effe758dd1c76eae5e3b5 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 9 Sep 2022 21:34:00 +0200 Subject: [PATCH 31/35] GH-153 - missing tests --- .../ForAsGenericMethodTests.cs | 8 ++--- .../ForAsNonGenericMethodTests.cs | 32 +++++-------------- .../ForPartsOfMethodTests.cs | 9 +++--- .../SubstituteFactoryCreateMethodTests.cs | 26 ++++----------- ...bstituteFactoryCreatePartialMethodTests.cs | 32 +++++-------------- ...stituteForInternalMemberCodeFixVerifier.cs | 25 +++++---------- .../ReturnsAsOrdinaryMethodTests.cs | 16 ++++++++++ .../ThrowsAsOrdinaryMethodTests.cs | 16 ++++++++++ .../ReceivedAsOrdinaryMethodTests.cs | 26 ++++++++++++++- .../ReceivedAsOrdinaryMethodTests.cs | 26 ++++++++++++++- .../ForAsGenericMethodTests.cs | 4 +++ .../ForPartsOfMethodTests.cs | 1 + .../ReceivedAsOrdinaryMethodTests.cs | 26 ++++++++++++++- .../CodeFixProviders/CodeFixVerifier.cs | 29 ++--------------- ...stituteForInternalMemberCodeFixVerifier.cs | 8 ++--- .../ForAsGenericMethodTests.cs | 9 +++--- .../ForAsNonGenericMethodTests.cs | 32 +++++-------------- .../ForPartsOfMethodTests.cs | 9 +++--- .../SubstituteFactoryCreateMethodTests.cs | 32 +++++-------------- ...bstituteFactoryCreatePartialMethodTests.cs | 32 +++++-------------- ...stituteForInternalMemberCodeFixVerifier.cs | 25 +++++---------- .../ReturnsAsOrdinaryMethodTests.cs | 18 +++++++++++ .../ThrowsAsOrdinaryMethodTests.cs | 18 +++++++++++ .../ReceivedAsOrdinaryMethodTests.cs | 26 ++++++++++++++- .../WhenAsOrdinaryMethodTests.cs | 2 ++ .../ReceivedAsOrdinaryMethodTests.cs | 25 ++++++++++++++- .../ReceivedAsOrdinaryMethodTests.cs | 25 ++++++++++++++- 27 files changed, 308 insertions(+), 229 deletions(-) diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs index 234aaad7..1e5ee102 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class ForAsGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -48,7 +48,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -86,7 +86,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"using System.Reflection; using NSubstitute; @@ -127,7 +127,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs index 108ed0ff..b32c2310 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class ForAsNonGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -20,8 +20,6 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,16 +41,14 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -66,8 +62,6 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -86,15 +80,13 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"using System.Reflection; using NSubstitute; @@ -110,8 +102,6 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -131,15 +121,13 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -157,8 +145,6 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -181,12 +167,10 @@ public class FooTests public void Test() { var substitute = Substitute.For(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = Substitute.For(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = Substitute.For(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs index 2c72a2a4..6e67719c 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class ForPartsOfMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -48,7 +48,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace @@ -86,8 +86,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( - int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"using System.Reflection; using NSubstitute; @@ -128,7 +127,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"using NSubstitute; namespace MyNamespace diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs index 1a671367..6335b118 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class SubstituteFactoryCreateMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -20,8 +20,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,16 +41,14 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -90,7 +86,7 @@ public void Test() await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"using System.Reflection; using NSubstitute.Core; @@ -106,8 +102,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -127,15 +121,13 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -153,8 +145,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -177,12 +167,10 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.Create(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs index 22a8a375..e315d48e 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public class SubstituteFactoryCreatePartialMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -20,8 +20,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } @@ -43,16 +41,14 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -66,8 +62,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -86,15 +80,13 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"using System.Reflection; using NSubstitute.Core; @@ -110,8 +102,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; @@ -131,15 +121,13 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"using NSubstitute.Core; namespace MyNamespace @@ -157,8 +145,6 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; @@ -181,12 +167,10 @@ public class FooTests public void Test() { var substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(new[] {typeof(Foo.Bar)}, null); - var otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy: new[] {typeof(Foo.Bar)}, constructorArguments: null); - var yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments: null, typesToProxy: new[] {typeof(Foo.Bar)}); } } }"; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs index cfff275c..c0139c3c 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; @@ -12,28 +10,21 @@ namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.SubstituteForI public abstract class SubstituteForInternalMemberCodeFixVerifier : CSharpCodeFixVerifier, ISubstituteForInternalMemberCodeFixVerifier { - public static IEnumerable DiagnosticIndicesTestCases => - Enumerable.Range(0, 3).Select(item => new object[] { item }); - protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; } = new SubstituteAnalyzer(); protected override CodeFixProvider CodeFixProvider { get; } = new SubstituteForInternalMemberCodeFixProvider(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index eb7f930a..5d6d4809 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -145,6 +145,22 @@ public void Test() {{ callInfo[0] = 1; }}, callInfo => {{}}); + {method}(value: substitute.Bar(Arg.Any()), returnThis: callInfo => + {{ + callInfo[0] = 1; + return 1; + }}).AndDoes(callInfo => + {{ + callInfo[0] = 1; + }}, callInfo => {{}}); + {method}(returnThis: callInfo => + {{ + callInfo[0] = 1; + return 1; + }}, value: substitute.Bar(Arg.Any())).AndDoes(callInfo => + {{ + callInfo[0] = 1; + }}, callInfo => {{}}); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index feee7b67..23153db6 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -142,6 +142,22 @@ public void Test() {{ callInfo[0] = 1; }}, callInfo => {{}}); + {method}(value: substitute.Bar(Arg.Any()), createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}).AndDoes(callInfo => + {{ + callInfo[0] = 1; + }}, callInfo => {{}}); + {method}(createException: callInfo => + {{ + callInfo[0] = 1; + return new Exception(); + }}, value: substitute.Bar(Arg.Any())).AndDoes(callInfo => + {{ + callInfo[0] = 1; + }}, callInfo => {{}}); }} }} diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 1b3e0b29..cc832228 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -480,17 +480,41 @@ public void Test() [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)")] public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) { var source = $@" diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 702e7c19..457001c8 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -158,17 +158,41 @@ public void Test() [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)")] public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) { var source = $@" diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs index 19bb6e70..6c93c706 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForAsGenericMethodTests.cs @@ -637,6 +637,8 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.For(1, 2, 3); + var otherSubstitute = NSubstitute.Substitute.For(new object[] { 1, 2, 3 }); + var yetAnotherSubstitute = NSubstitute.Substitute.For(constructorArguments: new object[] { 1, 2, 3 }); } } }"; @@ -661,6 +663,8 @@ public class FooTests public void Test() { var substitute = [|NSubstitute.Substitute.For(1)|]; + var otherSubstitute = [|NSubstitute.Substitute.For(new [] { 1 })|]; + var yetAnotherSubstitute = [|NSubstitute.Substitute.For(constructorArguments: new [] { 1 })|]; } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs index f809311e..04448137 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/SubstituteAnalyzerTests/ForPartsOfMethodTests.cs @@ -433,6 +433,7 @@ public class FooTests public void Test() { var substitute = NSubstitute.Substitute.ForPartsOf(1); + var otherSubstitute = NSubstitute.Substitute.ForPartsOf(constructorArguments: 1); } } }"; diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index fb4f1c44..3c13ac56 100644 --- a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -196,17 +196,41 @@ public void Test() [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.Received(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.Received(x: 1, y: 1, substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute: substitute, x: Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x: Quantity.None(), substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceive(x: 1, y: 1, substitute: substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute: substitute, x: 1, y: 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x: 1, y: 1, substitute: substitute)")] public override async Task ReportsNoDiagnostics_WhenUsedWithUnfortunatelyNamedMethod(string method) { var source = $@"using System; diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs index 51384e6e..c87ba991 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/CodeFixVerifier.cs @@ -25,34 +25,9 @@ protected CodeFixVerifier(WorkspaceFactory workspaceFactory) protected abstract DiagnosticAnalyzer DiagnosticAnalyzer { get; } - protected Task VerifyFix( - string oldSource, - string newSource) => - VerifyFix(oldSource, newSource, null, NSubstituteVersion.Latest); - - protected Task VerifyFix( - string oldSource, - string newSource, - int codeFixIndex) => - VerifyFix(oldSource, newSource, codeFixIndex, NSubstituteVersion.Latest); - - protected Task VerifyFix( - string oldSource, - string newSource, - NSubstituteVersion version) => - VerifyFix(oldSource, newSource, diagnosticIndex: null, codeFixIndex: null, version); - - protected Task VerifyFix( - string oldSource, - string newSource, - int? codeFixIndex = null, - NSubstituteVersion version = NSubstituteVersion.Latest) => - VerifyFix(oldSource, newSource, null, codeFixIndex, version); - protected async Task VerifyFix( string oldSource, string newSource, - int? diagnosticIndex = null, int? codeFixIndex = null, NSubstituteVersion version = NSubstituteVersion.Latest) { @@ -74,12 +49,12 @@ protected async Task VerifyFix( project.AnalyzerOptions); var previousAnalyzerDiagnostics = analyzerDiagnostics; - var attempts = !diagnosticIndex.HasValue ? analyzerDiagnostics.Length : 1; + var attempts = analyzerDiagnostics.Length; for (var i = 0; i < attempts; ++i) { var actions = new List(); - var context = new CodeFixContext(document, analyzerDiagnostics[diagnosticIndex ?? 0], (a, _) => actions.Add(a), CancellationToken.None); + var context = new CodeFixContext(document, analyzerDiagnostics[0], (a, _) => actions.Add(a), CancellationToken.None); await CodeFixProvider.RegisterCodeFixesAsync(context); if (!actions.Any()) diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs index 00e76875..f349df15 100644 --- a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/ISubstituteForInternalMemberCodeFixVerifier.cs @@ -4,13 +4,13 @@ namespace NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; public interface ISubstituteForInternalMemberCodeFixVerifier { - Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); + Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); - Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); + Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); - Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); + Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); - Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); + Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs index bfee457b..bbb2cba1 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsGenericMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public class ForAsGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute @@ -40,7 +40,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -72,8 +72,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( - int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -107,7 +106,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs index 598ca5b8..1fab19f5 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForAsNonGenericMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public class ForAsNonGenericMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -16,8 +16,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,17 +32,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -55,8 +51,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -71,16 +65,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -92,8 +84,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -109,16 +99,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -131,8 +119,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -149,13 +135,11 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = NSubstitute.Substitute.[For]({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = NSubstitute.Substitute.[For](typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = NSubstitute.Substitute.[For](constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs index a7de9762..a80fb9a4 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/ForPartsOfMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public class ForPartsOfMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute @@ -40,7 +40,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -72,8 +72,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty( - int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -107,7 +106,7 @@ End Namespace await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"Imports NSubstitute.Core diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs index 143fda60..6e463f04 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreateMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public class SubstituteFactoryCreateMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -16,8 +16,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,17 +32,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -55,8 +51,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -71,16 +65,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -92,8 +84,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -109,16 +99,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -131,8 +119,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -149,13 +135,11 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.Create({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.Create(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs index 59632db5..141e8da7 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteFactoryCreatePartialMethodTests.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public class SubstituteFactoryCreatePartialMethodTests : SubstituteForInternalMemberCodeFixVerifier { - public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -16,8 +16,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -34,17 +32,15 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -55,8 +51,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -71,16 +65,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty() { var oldSource = @"Imports System.Reflection Imports NSubstitute.Core @@ -92,8 +84,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace @@ -109,16 +99,14 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } - public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex) + public override async Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass() { var oldSource = @"Imports NSubstitute.Core @@ -131,8 +119,6 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace @@ -149,13 +135,11 @@ End Class Public Class FooTests Public Sub Test() Dim substitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial({GetType(Foo.Bar)}, Nothing) - Dim otherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(typesToProxy:= {GetType(Foo.Bar)}, constructorArguments:= Nothing) - Dim yetAnotherSubstitute = SubstitutionContext.Current.SubstituteFactory.CreatePartial(constructorArguments:= Nothing, typesToProxy:= {GetType(Foo.Bar)}) End Sub End Class End Namespace "; - await VerifyFix(oldSource, newSource, diagnosticIndex: diagnosticIndex); + await VerifyFix(oldSource, newSource); } public override async Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass() diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs index 105fcda2..50cf1d3d 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/SubstituteForInternalMemberCodeFixProviderTests/SubstituteForInternalMemberCodeFixVerifier.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; @@ -12,28 +10,21 @@ namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.Substitu public abstract class SubstituteForInternalMemberCodeFixVerifier : VisualBasicCodeFixVerifier, ISubstituteForInternalMemberCodeFixVerifier { - public static IEnumerable DiagnosticIndicesTestCases => - Enumerable.Range(0, 3).Select(item => new object[] { item }); - protected override DiagnosticAnalyzer DiagnosticAnalyzer { get; } = new SubstituteAnalyzer(); protected override CodeFixProvider CodeFixProvider { get; } = new SubstituteForInternalMemberCodeFixProvider(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalClass(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithInternalClass_AndArgumentListNotEmpty(); - [Theory] - [MemberData(nameof(DiagnosticIndicesTestCases))] - public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(int diagnosticIndex); + [Fact] + public abstract Task AppendsInternalsVisibleTo_WhenUsedWithNestedInternalClass(); [Fact] public abstract Task DoesNot_AppendsInternalsVisibleTo_WhenUsedWithPublicClass(); diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs index d3d239d6..f6e2b5c7 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ReturnsAsOrdinaryMethodTests.cs @@ -118,6 +118,24 @@ Return 1 Function(callInfo) callInfo(0) = 1 End Function) + {method}(value:= substitute.Bar(Arg.Any(Of Integer)()), returnThis:= Function(callInfo) + callInfo(0) = 1 + Return 1 + End Function).AndDoes(Function(callInfo) + callInfo(0) = 1 + End Function, + Function(callInfo) + callInfo(0) = 1 + End Function) + {method}(returnThis:= Function(callInfo) + callInfo(0) = 1 + Return 1 + End Function, value:= substitute.Bar(Arg.Any(Of Integer)())).AndDoes(Function(callInfo) + callInfo(0) = 1 + End Function, + Function(callInfo) + callInfo(0) = 1 + End Function) End Sub End Class diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs index c2126e96..35eca1f2 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ConflictingArgumentAssignmentsAnalyzerTests/ThrowsAsOrdinaryMethodTests.cs @@ -122,6 +122,24 @@ Return New Exception() Function(callInfo) callInfo(0) = 1 End Function) + {method}(value:= substitute.Bar(Arg.Any(Of Integer)()), createException:= Function(callInfo) + callInfo(0) = 1 + Return New Exception() + End Function).AndDoes(Function(callInfo) + callInfo(0) = 1 + End Function, + Function(callInfo) + callInfo(0) = 1 + End Function) + {method}(createException:= Function(callInfo) + callInfo(0) = 1 + Return New Exception() + End Function, value:= substitute.Bar(Arg.Any(Of Integer)())).AndDoes(Function(callInfo) + callInfo(0) = 1 + End Function, + Function(callInfo) + callInfo(0) = 1 + End Function) End Sub End Class diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 686d5cc6..ecfbc5e6 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -493,17 +493,41 @@ End Class [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.Received(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(x:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.Received(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.Received(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.Received(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.Received(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(x:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceive(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(x:= 1, y:= 1, substitute:= substitute)")] public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) { var source = $@"Imports System.Runtime.CompilerServices diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs index 26d5c5f1..e5d56e09 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonSubstitutableMemberWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -343,6 +343,8 @@ Public Class FooTests Public Sub Test() Dim substitute As Foo = Nothing {method}(substitute, {whenAction}, 1) + {method}(substitute:= substitute, substituteCall:= {whenAction}, x:= 1) + {method}(substituteCall:= {whenAction}, x:= 1, substitute:= substitute) End Sub End Class End Namespace diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 9d6cb281..c0293a40 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/ReceivedInReceivedInOrderAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -139,17 +139,40 @@ End Namespace [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.Received(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(substitute:= substitute, x: =Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(x:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.Received(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.Received(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.Received(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.Received(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(x:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceive(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(x:= 1, y:= 1, substitute:= substitute)")] public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string method) { var source = $@"Imports System diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs index 32d38598..5a38c2dd 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/UnusedReceivedAnalyzerTests/ReceivedAsOrdinaryMethodTests.cs @@ -185,17 +185,40 @@ End Namespace [CombinatoryData( "ReceivedExtensions.Received(substitute, Quantity.None())", + "ReceivedExtensions.Received(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.Received(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.Received(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.Received(Of Foo)(substitute:= substitute, x:= Quantity.None())", "SubstituteExtensions.Received(substitute, 1, 1)", + "SubstituteExtensions.Received(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.Received(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.Received(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.Received(Of Foo)(substitute:= substitute, x:= 1, y:=1)", + "SubstituteExtensions.Received(Of Foo)(x:= 1, y:=1, substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(x:= Quantity.None(), substitute:= substitute)", "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= Quantity.None())", + "ReceivedExtensions.ReceivedWithAnyArgs(Of Foo)(x:= Quantity.None(), substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.ReceivedWithAnyArgs(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceive(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceive(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceive(Of Foo)(x:= 1, y:= 1, substitute:= substitute)", "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute, 1, 1)", - "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)")] + "SubstituteExtensions.DidNotReceiveWithAnyArgs(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(x:= 1, y:= 1, substitute:= substitute)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute, 1, 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(substitute:= substitute, x:= 1, y:= 1)", + "SubstituteExtensions.DidNotReceiveWithAnyArgs(Of Foo)(x:= 1, y:= 1, substitute:= substitute)")] public override async Task ReportsNoDiagnostics_WhenUsedWithUnfortunatelyNamedMethod(string method) { var source = $@"Imports System From a2fa5cf3e7fdbb0c6f2bcae2d4d5e0559465a9eb Mon Sep 17 00:00:00 2001 From: tpodolak Date: Mon, 12 Sep 2022 00:01:51 +0200 Subject: [PATCH 32/35] GH-153 - clean-up --- ...actAsyncReceivedInOrderCallbackAnalyzer.cs | 5 +- .../AbstractCallInfoAnalyzer.cs | 5 +- ...tConflictingArgumentAssignmentsAnalyzer.cs | 5 +- .../AbstractNonSubstitutableMemberAnalyzer.cs | 5 +- ...stitutableMemberArgumentMatcherAnalyzer.cs | 9 +-- ...tNonSubstitutableMemberReceivedAnalyzer.cs | 5 +- ...stitutableMemberReceivedInOrderAnalyzer.cs | 5 +- ...tractNonSubstitutableMemberWhenAnalyzer.cs | 5 +- .../AbstractReEntrantSetupAnalyzer.cs | 13 ++--- ...stractReceivedInReceivedInOrderAnalyzer.cs | 11 ++-- .../AbstractSubstituteAnalyzer.cs | 5 +- .../AbstractSyncOverAsyncThrowsAnalyzer.cs | 5 +- .../AbstractUnusedReceivedAnalyzer.cs | 5 +- ...tractWithAnyArgsArgumentMatcherAnalyzer.cs | 5 +- .../ReEntrantCallFinder.cs | 58 ++++++++++++------- .../SubstitutionNodeFinder.cs | 31 +++++----- .../Extensions/CompilationExtensions.cs | 10 ++++ .../Extensions/IOperationExtensions.cs | 8 ++- 18 files changed, 93 insertions(+), 102 deletions(-) create mode 100644 src/NSubstitute.Analyzers.Shared/Extensions/CompilationExtensions.cs diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs index 9d947a63..148f8e0b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs @@ -30,10 +30,7 @@ protected sealed override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index ca0ad98d..cd004523 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -66,10 +66,7 @@ private bool SupportsCallInfo(Compilation compilation, IInvocationOperation invo private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (SupportsCallInfo(operationAnalysisContext.Compilation, invocationOperation) == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index 8075370d..5ce84e7d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -33,10 +33,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) { - if (syntaxNodeContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)syntaxNodeContext.Operation; if (invocationOperation.TargetMethod.IsAndDoesLikeMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs index 0a1a4801..1b7a66fb 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs @@ -38,10 +38,7 @@ protected sealed override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsReturnOrThrowLikeMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs index 0bea1753..07651474 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -46,19 +46,16 @@ protected override void InitializeAnalyzer(AnalysisContext context) context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(OperationAnalysisContext context) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (context.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsArgMatcherLikeMethod() == false) { return; } - AnalyzeArgLikeMethod(context, invocationOperation); + AnalyzeArgLikeMethod(operationAnalysisContext, invocationOperation); } private void AnalyzeArgLikeMethod( diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs index 4bfa9ead..91c74dd7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs @@ -34,10 +34,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) { - if (syntaxNodeContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)syntaxNodeContext.Operation; if (invocationOperation.Parent == null) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index 52d5ead1..ff44e10a 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -44,10 +44,7 @@ protected sealed override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs index 2301b16b..2d68ee7b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs @@ -38,10 +38,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext context) { - if (context.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)context.Operation; if (invocationOperation.TargetMethod.IsWhenLikeMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index a8e01ef4..6b00ee9d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -30,12 +30,9 @@ protected override void InitializeAnalyzer(AnalysisContext context) context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(OperationAnalysisContext context) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (context.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsInitialReEntryLikeMethod() == false) { @@ -46,18 +43,18 @@ private void AnalyzeInvocation(OperationAnalysisContext context) foreach (var argumentOperation in argumentOperations) { - if (IsPassedByParamsArrayOfCallInfoFunc(context.Compilation, argumentOperation)) + if (IsPassedByParamsArrayOfCallInfoFunc(operationAnalysisContext.Compilation, argumentOperation)) { continue; } if (IsPassedByParamsArray(argumentOperation)) { - AnalyzeParamsArgument(context, argumentOperation, invocationOperation); + AnalyzeParamsArgument(operationAnalysisContext, argumentOperation, invocationOperation); } else { - AnalyzeExpression(context, argumentOperation.Value, invocationOperation); + AnalyzeExpression(operationAnalysisContext, argumentOperation.Value, invocationOperation); } } } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs index 1f479626..0bc241fe 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs @@ -30,12 +30,9 @@ protected override void InitializeAnalyzer(AnalysisContext context) context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } - private void AnalyzeInvocation(OperationAnalysisContext context) + private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (context.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsReceivedInOrderMethod() == false) { @@ -43,7 +40,7 @@ private void AnalyzeInvocation(OperationAnalysisContext context) } foreach (var operation in _substitutionNodeFinder.FindForReceivedInOrderExpression( - context.Compilation, + operationAnalysisContext.Compilation, invocationOperation, includeAll: true).OfType()) { @@ -57,7 +54,7 @@ private void AnalyzeInvocation(OperationAnalysisContext context) operation.Syntax.GetLocation(), operation.TargetMethod.Name); - context.ReportDiagnostic(diagnostic); + operationAnalysisContext.ReportDiagnostic(diagnostic); } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs index 03ff5d74..b3a78376 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs @@ -51,10 +51,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; var methodSymbol = invocationOperation.TargetMethod; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs index 586d3abf..1fc0b2dd 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs @@ -31,10 +31,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsThrowSyncLikeMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs index c4d12b05..9009c519 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs @@ -30,10 +30,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext operationAnalysisContext) { - if (operationAnalysisContext.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (invocationOperation.TargetMethod.IsReceivedLikeMethod() == false) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs index c7e3da63..45bfdb5b 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs @@ -36,10 +36,7 @@ protected override void InitializeAnalyzer(AnalysisContext context) private void AnalyzeInvocation(OperationAnalysisContext context) { - if (context.Operation is not IInvocationOperation invocationOperation) - { - return; - } + var invocationOperation = (IInvocationOperation)context.Operation; var methodSymbol = invocationOperation.TargetMethod; if (methodSymbol.IsWithAnyArgsIncompatibleArgMatcherLikeMethod()) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 5d078b0b..961124fa 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -50,7 +51,7 @@ private IEnumerable GetPotentialOtherSubstituteInvocations } } - private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol rootNodeSymbol) + private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compilation, IOperation rootOperation, ISymbol? rootNodeSymbol) { if (rootNodeSymbol == null) { @@ -59,7 +60,7 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compi var rootIdentifierNode = GetLocalReferenceOperation(rootOperation); - var rootIdentifierSymbol = rootIdentifierNode?.ExtractSymbol(); + var rootIdentifierSymbol = rootIdentifierNode.ExtractSymbol(); if (rootIdentifierSymbol == null) { @@ -78,7 +79,12 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compi var substitutedNode = _substitutionNodeFinder.FindForStandardExpression(operation); - var substituteNodeSymbol = substitutedNode?.ExtractSymbol(); + if (substitutedNode == null) + { + yield break; + } + + var substituteNodeSymbol = substitutedNode.ExtractSymbol(); if (substituteNodeSymbol == null) { @@ -101,18 +107,22 @@ private IEnumerable GetOtherSubstitutionsForSymbol(Compilation compi private static IEnumerable GetConstructorOperations(Compilation compilation, ISymbol fieldReferenceOperation) { - // TODO naming - foreach (var location in fieldReferenceOperation.ContainingType.GetMembers().OfType() - .Where(methodSymbol => methodSymbol.MethodKind is MethodKind.Constructor or MethodKind.StaticConstructor && methodSymbol.Locations.Length > 0) + SemanticModel? semanticModel = null; + foreach (var constructorLocation in fieldReferenceOperation.ContainingType.Constructors + .Where(methodSymbol => methodSymbol.Locations.Length > 0) .SelectMany(x => x.Locations) .Where(location => location.IsInSource)) { - var root = location.SourceTree.GetRoot(); - var relatedNode = root.FindNode(location.SourceSpan); + var root = constructorLocation.SourceTree.GetRoot(); + var relatedNode = root.FindNode(constructorLocation.SourceSpan); + + // perf - take original semantic model whenever possible + // but keep in mind that we might traverse outside of the original one https://github.com/nsubstitute/NSubstitute.Analyzers/issues/56 + semanticModel = semanticModel == null || semanticModel.SyntaxTree != constructorLocation.SourceTree + ? compilation.TryGetSemanticModel(constructorLocation.SourceTree) + : semanticModel; - // TODO reuse semantic model - var semanticModel = compilation.GetSemanticModel(location.SourceTree); - var operation = semanticModel.GetOperation(relatedNode) ?? semanticModel.GetOperation(relatedNode.Parent); + var operation = semanticModel?.GetOperation(relatedNode) ?? semanticModel?.GetOperation(relatedNode.Parent); if (operation is not null) { @@ -121,9 +131,9 @@ private static IEnumerable GetConstructorOperations(Compilation comp } } - private IOperation GetLocalReferenceOperation(IOperation node) + private IOperation? GetLocalReferenceOperation(IOperation? node) { - var child = node.Children.FirstOrDefault(); + var child = node?.Children.FirstOrDefault(); return child is ILocalReferenceOperation or IFieldReferenceOperation ? child : null; } @@ -140,7 +150,7 @@ private class ReEntrantCallVisitor : OperationWalker private readonly Compilation _compilation; private readonly HashSet _visitedOperations = new(); private readonly List _invocationOperation = new(); - private readonly Dictionary _semanticModelCache = new(1); + private SemanticModel? _semanticModel; public ImmutableList InvocationOperations => _invocationOperation.ToImmutableList(); @@ -175,24 +185,30 @@ private void VisitRelatedSymbols(IInvocationOperation invocationOperation) var root = location.SourceTree.GetRoot(); var relatedNode = root.FindNode(location.SourceSpan); var semanticModel = GetSemanticModel(relatedNode); + + if (semanticModel == null) + { + continue; + } + var operation = semanticModel.GetOperation(relatedNode) ?? semanticModel.GetOperation(relatedNode.Parent); Visit(operation); } } - private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) + private SemanticModel? GetSemanticModel(SyntaxNode syntaxNode) { var syntaxTree = syntaxNode.SyntaxTree; - if (_semanticModelCache.TryGetValue(syntaxTree, out var semanticModel)) + + // perf - take original semantic model whenever possible + // but keep in mind that we might traverse outside of the original one https://github.com/nsubstitute/NSubstitute.Analyzers/issues/56 + if (_semanticModel == null || _semanticModel.SyntaxTree != syntaxTree) { - return semanticModel; + _semanticModel = _compilation.TryGetSemanticModel(syntaxTree); } - semanticModel = _compilation.GetSemanticModel(syntaxTree); - _semanticModelCache[syntaxTree] = semanticModel; - - return semanticModel; + return _semanticModel; } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 92e5c4bb..83b80a85 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Linq; @@ -13,7 +14,7 @@ internal class SubstitutionNodeFinder : ISubstitutionNodeFinder public IEnumerable Find( Compilation compilation, - IInvocationOperation invocationOperation) + IInvocationOperation? invocationOperation) { if (invocationOperation == null) { @@ -51,7 +52,7 @@ public IEnumerable Find( return standardSubstitution != null ? new[] { standardSubstitution } : Enumerable.Empty(); } - public IEnumerable FindForWhenExpression(Compilation compilation, IInvocationOperation invocationOperation) + public IEnumerable FindForWhenExpression(Compilation compilation, IInvocationOperation? invocationOperation) { if (invocationOperation == null) { @@ -86,7 +87,7 @@ public IEnumerable FindForReceivedInOrderExpression( return visitor.Operations; } - public IOperation FindForStandardExpression(IInvocationOperation invocationOperation) + public IOperation? FindForStandardExpression(IInvocationOperation invocationOperation) { return invocationOperation.GetSubstituteOperation(); } @@ -106,7 +107,7 @@ private static IEnumerable GetBaseTypesAndThis(ITypeSymbol type) } } - private IOperation FindForAndDoesExpression(IInvocationOperation invocationOperation) + private IOperation? FindForAndDoesExpression(IInvocationOperation invocationOperation) { if (invocationOperation.GetSubstituteOperation() is not IInvocationOperation parentInvocationOperation) { @@ -123,7 +124,7 @@ private class WhenVisitor : OperationWalker private readonly bool _includeAll; private readonly HashSet _operations = new(); - private readonly Dictionary _semanticModelCache = new(1); + private SemanticModel? _semanticModel; public WhenVisitor( Compilation compilation, @@ -150,9 +151,13 @@ public override void VisitMethodReference(IMethodReferenceOperation operation) { foreach (var methodDeclaringSyntaxReference in operation.Method.DeclaringSyntaxReferences) { - // TODO async? var syntaxNode = methodDeclaringSyntaxReference.GetSyntax(); var semanticModel = GetSemanticModel(syntaxNode.Parent); + if (semanticModel is null) + { + continue; + } + var referencedOperation = semanticModel.GetOperation(syntaxNode) ?? semanticModel.GetOperation(syntaxNode.Parent); Visit(referencedOperation); @@ -193,18 +198,18 @@ private void TryAdd(IOperation operation) } } - private SemanticModel GetSemanticModel(SyntaxNode syntaxNode) + private SemanticModel? GetSemanticModel(SyntaxNode syntaxNode) { var syntaxTree = syntaxNode.SyntaxTree; - if (_semanticModelCache.TryGetValue(syntaxTree, out var semanticModel)) + + // perf - take original semantic model whenever possible + // but keep in mind that we might traverse outside of the original one https://github.com/nsubstitute/NSubstitute.Analyzers/issues/56 + if (_semanticModel == null || _semanticModel.SyntaxTree != syntaxTree) { - return semanticModel; + _semanticModel = _compilation.TryGetSemanticModel(syntaxTree); } - semanticModel = _compilation.GetSemanticModel(syntaxTree); - _semanticModelCache[syntaxTree] = semanticModel; - - return semanticModel; + return _semanticModel; } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/CompilationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/CompilationExtensions.cs new file mode 100644 index 00000000..884f7dc7 --- /dev/null +++ b/src/NSubstitute.Analyzers.Shared/Extensions/CompilationExtensions.cs @@ -0,0 +1,10 @@ +#nullable enable +using Microsoft.CodeAnalysis; + +namespace NSubstitute.Analyzers.Shared.Extensions; + +internal static class CompilationExtensions +{ + public static SemanticModel? TryGetSemanticModel(this Compilation compilation, SyntaxTree syntaxTree) => + compilation.ContainsSyntaxTree(syntaxTree) ? compilation.GetSemanticModel(syntaxTree) : null; +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs index 1c32ba01..1e30604e 100644 --- a/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs +++ b/src/NSubstitute.Analyzers.Shared/Extensions/IOperationExtensions.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; @@ -22,7 +23,7 @@ public static bool IsEventAssignmentOperation(this IOperation operation) public static IOperation GetSubstituteOperation(this IPropertyReferenceOperation propertyReferenceOperation) => propertyReferenceOperation.Instance; - public static IOperation GetSubstituteOperation(this IInvocationOperation invocationOperation) + public static IOperation? GetSubstituteOperation(this IInvocationOperation invocationOperation) { if (invocationOperation.Instance != null) { @@ -110,7 +111,7 @@ public static IEnumerable Ancestors(this IOperation operation) } } - public static ISymbol ExtractSymbol(this IOperation operation) + public static ISymbol? ExtractSymbol(this IOperation? operation) { var symbol = operation switch { @@ -122,10 +123,11 @@ public static ISymbol ExtractSymbol(this IOperation operation) IFieldReferenceOperation fieldReferenceOperation => fieldReferenceOperation.Field, _ => null }; + return symbol; } - public static IEnumerable GetArrayElementValues(this IOperation operation) + public static IEnumerable? GetArrayElementValues(this IOperation operation) { return operation switch { From 9529446dbf940322df52a19d8b2b72040398d865 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 2 Oct 2022 21:06:40 +0200 Subject: [PATCH 33/35] GH-153 - code fix providers clean-up --- ...ternalSetupSpecificationCodeFixProvider.cs | 22 ++++++++---- ...stituteForInternalMemberCodeFixProvider.cs | 4 +-- ...dInternalsVisibleToAttributeRefactoring.cs | 7 ++-- .../Refactorings/AddModifierRefactoring.cs | 5 +-- .../ReplaceModifierRefactoring.cs | 10 ++++-- ...torArgumentsForInterfaceCodeFixProvider.cs | 15 +++----- ...ternalSetupSpecificationCodeFixProvider.cs | 36 +++++++++++-------- ...teUsedForUnsupportedTypeCodeFixProvider.cs | 12 ++----- .../AbstractReEntrantSetupCodeFixProvider.cs | 12 ++----- ...eceivedInReceivedInOrderCodeFixProvider.cs | 16 ++++----- ...stituteForInternalMemberCodeFixProvider.cs | 12 ++----- ...tractSuppressDiagnosticsCodeFixProvider.cs | 18 ++++++---- ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 12 ++----- ...ternalSetupSpecificationCodeFixProvider.cs | 22 ++++++++---- ...stituteForInternalMemberCodeFixProvider.cs | 4 +-- ...dInternalsVisibleToAttributeRefactoring.cs | 7 ++-- .../Refactorings/AddModifierRefactoring.cs | 9 +++-- .../ReplaceModifierRefactoring.cs | 10 ++++-- 18 files changed, 121 insertions(+), 112 deletions(-) diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs index a8835395..a8f81c15 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; @@ -12,18 +13,27 @@ internal sealed class InternalSetupSpecificationCodeFixProvider : AbstractIntern { protected override string ReplaceModifierCodeFixTitle { get; } = "Replace internal with public modifier"; - protected override Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility) + protected override Task AddModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility accessibility, + CancellationToken cancellationToken) { - return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility); + return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility, cancellationToken); } - protected override Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + protected override Task ReplaceModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility fromAccessibility, + Accessibility toAccessibility, + CancellationToken cancellationToken) { - return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility); + return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility, cancellationToken); } - protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { - AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, compilationUnitSyntax); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index d5208f6d..f048e7d4 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -15,8 +15,8 @@ public SubstituteForInternalMemberCodeFixProvider() { } - protected override void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + protected override void RegisterCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { - AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, compilationUnitSyntax); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs index f0c67fd2..387235a8 100644 --- a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs @@ -13,7 +13,7 @@ namespace NSubstitute.Analyzers.CSharp.Refactorings; internal static class AddInternalsVisibleToAttributeRefactoring { - public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken = default) + public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken) { var attributeList = GetGenerator(document) .InternalVisibleToDynamicProxyAttributeList() @@ -25,12 +25,11 @@ public static Task RefactorAsync(Document document, CompilationUnitSyn return document.ReplaceNodeAsync(compilationUnitSyntax, updatedCompilationUnitSyntax, cancellationToken); } - public static void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + public static void RegisterCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { var codeAction = CodeAction.Create( "Add InternalsVisibleTo attribute", - cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken), - diagnostic.Id); + cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken)); context.RegisterCodeFix(codeAction, context.Diagnostics); } diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs index 18c17dcf..67871d35 100644 --- a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -10,7 +11,7 @@ namespace NSubstitute.Analyzers.CSharp.Refactorings; internal static class AddModifierRefactoring { - public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) + public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility, CancellationToken cancellationToken) { var syntaxKind = accessibility switch { @@ -20,7 +21,7 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A var newNode = Insert(node, syntaxKind); - return document.ReplaceNodeAsync(node, newNode); + return document.ReplaceNodeAsync(node, newNode, cancellationToken: cancellationToken); } private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs index 9bc6e64b..ffa98981 100644 --- a/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -11,14 +12,19 @@ namespace NSubstitute.Analyzers.CSharp.Refactorings; internal class ReplaceModifierRefactoring { - public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + public static Task RefactorAsync( + Document document, + SyntaxNode node, + Accessibility fromAccessibility, + Accessibility toAccessibility, + CancellationToken cancellationToken) { var fromSyntaxKind = InferSyntaxKind(fromAccessibility); var toSyntaxKind = InferSyntaxKind(toAccessibility); var newNode = ReplaceModifier(node, fromSyntaxKind, toSyntaxKind); - return document.ReplaceNodeAsync(node, newNode); + return document.ReplaceNodeAsync(node, newNode, cancellationToken: cancellationToken); } private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs index ae4ad0c1..ca16fdbc 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -20,18 +20,11 @@ internal abstract class AbstractConstructorArgumentsForInterfaceCodeFixProvider public override Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => - diag.Descriptor.Id == DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); - if (diagnostic == null) - { - return Task.CompletedTask; - } - var codeAction = CodeAction.Create( "Remove constructor arguments", - ct => CreateChangedDocument(ct, context, diagnostic), + ct => CreateChangedDocument(context, ct), nameof(AbstractConstructorArgumentsForInterfaceCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + context.RegisterCodeFix(codeAction, context.Diagnostics); return Task.CompletedTask; } @@ -40,13 +33,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) protected abstract SyntaxNode GetInvocationExpressionSyntaxWithNullConstructorArgument(IInvocationOperation invocationOperation); - private async Task CreateChangedDocument(CancellationToken cancellationToken, CodeFixContext context, Diagnostic diagnostic) + private async Task CreateChangedDocument(CodeFixContext context, CancellationToken cancellationToken) { var documentEditor = await DocumentEditor.CreateAsync(context.Document, cancellationToken); var root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var invocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var invocation = root.FindNode(context.Span, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken); if (semanticModel.GetOperation(invocation) is not IInvocationOperation invocationOperation) { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs index 338a1474..b9e8a90c 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; @@ -16,16 +17,8 @@ internal abstract class AbstractInternalSetupSpecificationCodeFixProvider diag.Id == DiagnosticIdentifiers.InternalSetupSpecification); - - if (diagnostic == null) - { - return; - } - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var invocationExpression = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var invocationExpression = root.FindNode(context.Span, getInnermostNodeForTie: true); var syntaxReference = await GetDeclaringSyntaxReference(context, invocationExpression); if (syntaxReference == null) @@ -40,8 +33,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - context.RegisterCodeFix(CodeAction.Create("Add protected modifier", token => AddModifierRefactoring(context.Document, syntaxNode, Accessibility.Protected)), diagnostic); - context.RegisterCodeFix(CodeAction.Create(ReplaceModifierCodeFixTitle, token => ReplaceModifierRefactoring(context.Document, syntaxNode, Accessibility.Internal, Accessibility.Public)), diagnostic); + context.RegisterCodeFix( + CodeAction.Create("Add protected modifier", token => AddModifierRefactoring(context.Document, syntaxNode, Accessibility.Protected, token)), + context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create(ReplaceModifierCodeFixTitle, token => ReplaceModifierRefactoring(context.Document, syntaxNode, Accessibility.Internal, Accessibility.Public, token)), + context.Diagnostics); var compilationUnitSyntax = FindCompilationUnitSyntax(syntaxNode); @@ -50,14 +47,23 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - RegisterAddInternalsVisibleToAttributeCodeFix(context, diagnostic, compilationUnitSyntax); + RegisterAddInternalsVisibleToAttributeCodeFix(context, compilationUnitSyntax); } - protected abstract Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility); + protected abstract Task AddModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility accessibility, + CancellationToken cancellationToken); - protected abstract Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility); + protected abstract Task ReplaceModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility fromAccessibility, + Accessibility toAccessibility, + CancellationToken cancellationToken); - protected abstract void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, TCompilationUnitSyntax compilationUnitSyntax); + protected abstract void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, TCompilationUnitSyntax compilationUnitSyntax); private async Task GetDeclaringSyntaxReference(CodeFixContext context, SyntaxNode invocationExpression) { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index 66b50d54..bb836a5a 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -19,15 +18,8 @@ internal abstract class AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixPr public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => - diag.Descriptor.Id == DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); - if (diagnostic == null) - { - return; - } - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var syntaxNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var syntaxNode = root.FindNode(context.Span, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); if (semanticModel.GetOperation(syntaxNode) is not IInvocationOperation invocationOperation) @@ -43,7 +35,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) title, ct => CreateChangedDocument(context, invocationOperation, ct), nameof(AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + context.RegisterCodeFix(codeAction, context.Diagnostics); } protected abstract SyntaxNode UpdateInvocationExpression( diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs index 74b37789..0bbd8718 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReEntrantSetupCodeFixProvider.cs @@ -20,17 +20,9 @@ internal abstract class AbstractReEntrantSetupCodeFixProvider : public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => - diag.Descriptor.Id == DiagnosticIdentifiers.ReEntrantSubstituteCall); - - if (diagnostic == null) - { - return; - } - var semanticModel = await context.Document.GetSemanticModelAsync(); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken); - var node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var node = root.FindNode(context.Span, getInnermostNodeForTie: true); if (semanticModel.GetOperation(node) is not { } nodeOperation) { @@ -59,7 +51,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) ct => CreateChangedDocument(context, semanticModel, invocationOperation, methodSymbol, ct), nameof(AbstractReEntrantSetupCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + context.RegisterCodeFix(codeAction, context.Diagnostics); } protected abstract string LambdaParameterName { get; } diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs index ece0079f..d79ce447 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs @@ -18,21 +18,21 @@ internal abstract class AbstractReceivedInReceivedInOrderCodeFixProvider : CodeF public override Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => diag.Descriptor.Id == DiagnosticIdentifiers.ReceivedUsedInReceivedInOrder); - if (diagnostic != null) - { - var codeAction = CodeAction.Create("Remove redundant Received checks", ct => CreateChangedDocument(ct, context, diagnostic), nameof(AbstractReceivedInReceivedInOrderCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); - } + var codeAction = CodeAction.Create( + "Remove redundant Received checks", + ct => CreateChangedDocument(ct, context), + nameof(AbstractReceivedInReceivedInOrderCodeFixProvider)); + + context.RegisterCodeFix(codeAction, context.Diagnostics); return Task.CompletedTask; } - private async Task CreateChangedDocument(CancellationToken cancellationToken, CodeFixContext context, Diagnostic diagnostic) + private async Task CreateChangedDocument(CancellationToken cancellationToken, CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var invocation = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var invocation = root.FindNode(context.Span, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken); if (semanticModel.GetOperation(invocation) is not IInvocationOperation invocationOperation) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index ba865025..7b127dbc 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -21,15 +21,9 @@ protected AbstractSubstituteForInternalMemberCodeFixProvider(ISubstituteProxyAna public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = context.Diagnostics.FirstOrDefault(diag => diag.Descriptor.Id == DiagnosticIdentifiers.SubstituteForInternalMember); - if (diagnostic == null) - { - return; - } - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var invocationExpression = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var invocationExpression = root.FindNode(context.Span, getInnermostNodeForTie: true); var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); if (semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) @@ -52,10 +46,10 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + RegisterCodeFix(context, compilationUnitSyntax); } - protected abstract void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, TCompilationUnitSyntax compilationUnitSyntax); + protected abstract void RegisterCodeFix(CodeFixContext context, TCompilationUnitSyntax compilationUnitSyntax); private SyntaxReference GetDeclaringSyntaxReference(IInvocationOperation invocationOperation) { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs index 22fe430b..aeff83ed 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSuppressDiagnosticsCodeFixProvider.cs @@ -36,8 +36,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await context.Document.GetSyntaxRootAsync(); var model = await context.Document.GetSemanticModelAsync(); - foreach (var diagnostic in context.Diagnostics - .Where(diagnostic => FixableDiagnosticIds.Contains(diagnostic.Id))) + foreach (var diagnostic in context.Diagnostics) { var syntaxNode = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); var symbolInfo = model.GetSymbolInfo(syntaxNode); @@ -47,7 +46,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix( CodeAction.Create( CreateCodeFixTitle(diagnostic, innerSymbol), - cancellationToken => GetTransformedSolutionAsync(context, diagnostic, settingsFile, innerSymbol)), + cancellationToken => GetTransformedSolutionAsync(context, diagnostic, settingsFile, innerSymbol, cancellationToken)), diagnostic); } } @@ -93,7 +92,12 @@ private static string GetSymbolTitlePrefix(ISymbol innerSymbol) }; } - private Task GetTransformedSolutionAsync(CodeFixContext context, Diagnostic diagnostic, TextDocument settingsFile, ISymbol symbol) + private Task GetTransformedSolutionAsync( + CodeFixContext context, + Diagnostic diagnostic, + TextDocument settingsFile, + ISymbol symbol, + CancellationToken cancellationToken) { var project = context.Document.Project; var settingsFileId = settingsFile?.Id; @@ -106,7 +110,7 @@ private Task GetTransformedSolutionAsync(CodeFixContext context, Diagn settingsFileId = DocumentId.CreateNewId(project.Id); } - var options = GetUpdatedAnalyzersOptions(context, diagnostic, symbol); + var options = GetUpdatedAnalyzersOptions(context, diagnostic, symbol, cancellationToken); var solution = project.Solution; @@ -118,9 +122,9 @@ private Task GetTransformedSolutionAsync(CodeFixContext context, Diagn return Task.FromResult(solution); } - private static AnalyzersSettings GetUpdatedAnalyzersOptions(CodeFixContext context, Diagnostic diagnostic, ISymbol symbol) + private static AnalyzersSettings GetUpdatedAnalyzersOptions(CodeFixContext context, Diagnostic diagnostic, ISymbol symbol, CancellationToken cancellationToken) { - var options = context.Document.Project.AnalyzerOptions.GetSettings(default(CancellationToken)); + var options = context.Document.Project.AnalyzerOptions.GetSettings(cancellationToken); var target = CreateSuppressionTarget(symbol); options.Suppressions ??= new List(); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 25c83925..fd73d813 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -28,17 +28,9 @@ protected AbstractSyncOverAsyncThrowsCodeFixProvider(ISubstitutionNodeFinder sub public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostic = - context.Diagnostics.FirstOrDefault(diag => diag.Descriptor.Id == DiagnosticIdentifiers.SyncOverAsyncThrows); - - if (diagnostic == null) - { - return; - } - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocationExpression) + if (root.FindNode(context.Span, getInnermostNodeForTie: true) is not { } invocationExpression) { return; } @@ -63,7 +55,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ct => CreateChangedDocument(context, semanticModel, invocationOperation, supportsThrowsAsync, ct), nameof(AbstractSyncOverAsyncThrowsCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + context.RegisterCodeFix(codeAction, context.Diagnostics); } protected abstract SyntaxNode UpdateMemberExpression(IInvocationOperation invocationOperation, SyntaxNode updatedNameSyntax); diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs index a933ded7..04731097 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; @@ -12,18 +13,27 @@ internal sealed class InternalSetupSpecificationCodeFixProvider : AbstractIntern { protected override string ReplaceModifierCodeFixTitle { get; } = "Replace friend with public modifier"; - protected override Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility) + protected override Task AddModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility accessibility, + CancellationToken cancellationToken) { - return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility); + return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility, cancellationToken); } - protected override Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + protected override Task ReplaceModifierRefactoring( + Document document, + SyntaxNode node, + Accessibility fromAccessibility, + Accessibility toAccessibility, + CancellationToken cancellationToken) { - return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility); + return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility, cancellationToken); } - protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { - AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, compilationUnitSyntax); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index 13456f8b..b9f97f41 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -15,8 +15,8 @@ public SubstituteForInternalMemberCodeFixProvider() { } - protected override void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + protected override void RegisterCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { - AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, compilationUnitSyntax); } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs index e3d61870..d86e301b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs @@ -14,7 +14,7 @@ namespace NSubstitute.Analyzers.VisualBasic.Refactorings; internal static class AddInternalsVisibleToAttributeRefactoring { - public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken = default) + public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken) { var attributeList = GetGenerator(document) .InternalVisibleToDynamicProxyAttributeList() @@ -31,12 +31,11 @@ public static Task RefactorAsync(Document document, CompilationUnitSyn return document.ReplaceNodeAsync(compilationUnitSyntax, updatedCompilationUnitSyntax, cancellationToken); } - public static void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + public static void RegisterCodeFix(CodeFixContext context, CompilationUnitSyntax compilationUnitSyntax) { var codeAction = CodeAction.Create( "Add InternalsVisibleTo attribute", - cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken), - diagnostic.Id); + cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken)); context.RegisterCodeFix(codeAction, context.Diagnostics); } diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs index 9f785ece..5d05de24 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; @@ -10,7 +11,11 @@ namespace NSubstitute.Analyzers.VisualBasic.Refactorings; internal static class AddModifierRefactoring { - public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) + public static Task RefactorAsync( + Document document, + SyntaxNode node, + Accessibility accessibility, + CancellationToken cancellationToken) { var syntaxKind = accessibility switch { @@ -20,7 +25,7 @@ public static Task RefactorAsync(Document document, SyntaxNode node, A var newNode = Insert(node, syntaxKind); - return document.ReplaceNodeAsync(node, newNode); + return document.ReplaceNodeAsync(node, newNode, cancellationToken: cancellationToken); } private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs index 535ece9c..aa2735d6 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; @@ -11,14 +12,19 @@ namespace NSubstitute.Analyzers.VisualBasic.Refactorings; internal class ReplaceModifierRefactoring { - public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + public static Task RefactorAsync( + Document document, + SyntaxNode node, + Accessibility fromAccessibility, + Accessibility toAccessibility, + CancellationToken cancellationToken) { var fromSyntaxKind = InferSyntaxKind(fromAccessibility); var toSyntaxKind = InferSyntaxKind(toAccessibility); var newNode = ReplaceModifier(node, fromSyntaxKind, toSyntaxKind); - return document.ReplaceNodeAsync(node, newNode); + return document.ReplaceNodeAsync(node, newNode, cancellationToken: cancellationToken); } private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) From a43bc3574f3bf2a0466e9bc3e08d53c774aa3528 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 2 Oct 2022 21:15:11 +0200 Subject: [PATCH 34/35] GH-153 - adding missing sealed modifiers --- .../CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs | 2 +- .../CSharp/CSharpSolutionLoader.cs | 2 +- .../Shared/AnalyzerBenchmark.cs | 2 +- .../VisualBasic/VisualBasicDiagnosticAnalyzersBenchmarks.cs | 2 +- .../VisualBasic/VisualBasicSolutionLoader.cs | 2 +- .../DiagnosticAnalyzers/SubstituteConstructorMatcher.cs | 2 +- ...stractConstructorArgumentsForInterfaceCodeFixProvider.cs | 6 +++--- .../AbstractInternalSetupSpecificationCodeFixProvider.cs | 4 ++-- ...mberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs | 2 +- ...SubstitutableMemberSuppressDiagnosticsCodeFixProvider.cs | 2 +- ...artialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs | 6 +++--- .../AbstractReceivedInReceivedInOrderCodeFixProvider.cs | 6 +++--- .../AbstractSubstituteForInternalMemberCodeFixProvider.cs | 4 ++-- .../AbstractSyncOverAsyncThrowsCodeFixProvider.cs | 6 +++--- .../AbstractAsyncReceivedInOrderCallbackAnalyzer.cs | 2 +- .../DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs | 4 ++-- .../AbstractConflictingArgumentAssignmentsAnalyzer.cs | 4 ++-- .../AbstractNonSubstitutableMemberAnalyzer.cs | 4 ++-- ...AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs | 4 ++-- .../AbstractNonSubstitutableMemberReceivedAnalyzer.cs | 6 +++--- ...AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs | 4 ++-- .../AbstractNonSubstitutableMemberWhenAnalyzer.cs | 6 +++--- .../DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs | 4 ++-- .../AbstractReceivedInReceivedInOrderAnalyzer.cs | 4 ++-- .../DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs | 4 ++-- .../AbstractSyncOverAsyncThrowsAnalyzer.cs | 4 ++-- .../DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs | 4 ++-- .../AbstractWithAnyArgsArgumentMatcherAnalyzer.cs | 4 ++-- .../DiagnosticAnalyzers/CallInfoFinder.cs | 4 ++-- .../DiagnosticAnalyzers/ReEntrantCallFinder.cs | 2 +- .../DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs | 2 +- .../DiagnosticAnalyzers/SubstituteProxyAnalysis.cs | 2 +- .../DiagnosticAnalyzers/SubstitutionNodeFinder.cs | 2 +- .../DiagnosticAnalyzers/SubstituteConstructorMatcher.cs | 2 +- 34 files changed, 60 insertions(+), 60 deletions(-) diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs index 252fe780..a94bce65 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpDiagnosticAnalyzersBenchmarks.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Benchmarks.CSharp; -public class CSharpDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks +public sealed class CSharpDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks { protected override AnalyzerBenchmark CallInfoAnalyzerBenchmark { get; } diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpSolutionLoader.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpSolutionLoader.cs index 8e99e214..da01e566 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpSolutionLoader.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/CSharp/CSharpSolutionLoader.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Benchmarks.CSharp; -public class CSharpSolutionLoader : AbstractSolutionLoader +public sealed class CSharpSolutionLoader : AbstractSolutionLoader { protected override string DocumentFileExtension { get; } = ".cs"; diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs index 8f7ffda2..7faee069 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/Shared/AnalyzerBenchmark.cs @@ -11,7 +11,7 @@ namespace NSubstitute.Analyzers.Benchmarks.Shared; -public class AnalyzerBenchmark +public sealed class AnalyzerBenchmark { private readonly BenchmarkAnalyzer _benchmarkAnalyzer; private readonly Solution _solution; diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicDiagnosticAnalyzersBenchmarks.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicDiagnosticAnalyzersBenchmarks.cs index 0d1a495d..d784e83b 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicDiagnosticAnalyzersBenchmarks.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicDiagnosticAnalyzersBenchmarks.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Benchmarks.VisualBasic; -public class VisualBasicDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks +public sealed class VisualBasicDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks { protected override AnalyzerBenchmark CallInfoAnalyzerBenchmark { get; } diff --git a/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicSolutionLoader.cs b/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicSolutionLoader.cs index df518a96..07572bfa 100644 --- a/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicSolutionLoader.cs +++ b/benchmarks/NSubstitute.Analyzers.Benchmarks/VisualBasic/VisualBasicSolutionLoader.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Benchmarks.VisualBasic; -public class VisualBasicSolutionLoader : AbstractSolutionLoader +public sealed class VisualBasicSolutionLoader : AbstractSolutionLoader { protected override string DocumentFileExtension { get; } = ".vb"; diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index 9fb57a31..87396f8e 100644 --- a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; -internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher +internal sealed class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { public static SubstituteConstructorMatcher Instance { get; } = new(); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs index ca16fdbc..8876699a 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractConstructorArgumentsForInterfaceCodeFixProvider.cs @@ -13,12 +13,12 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal abstract class AbstractConstructorArgumentsForInterfaceCodeFixProvider : CodeFixProvider { - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SubstituteConstructorArgumentsForInterface); - public override Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var codeAction = CodeAction.Create( "Remove constructor arguments", diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs index b9e8a90c..a1d89fc8 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs @@ -11,11 +11,11 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal abstract class AbstractInternalSetupSpecificationCodeFixProvider : CodeFixProvider where TCompilationUnitSyntax : SyntaxNode { - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.InternalSetupSpecification); + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.InternalSetupSpecification); protected abstract string ReplaceModifierCodeFixTitle { get; } - public override async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var invocationExpression = root.FindNode(context.Span, getInnermostNodeForTie: true); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs index 4347603a..0737b5dc 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider.cs @@ -10,7 +10,7 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal abstract class AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider { - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.NonSubstitutableMemberArgumentMatcherUsage); + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.NonSubstitutableMemberArgumentMatcherUsage); protected override IEnumerable GetSuppressibleSymbol(SemanticModel model, SyntaxNode syntaxNode, ISymbol symbol) { diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberSuppressDiagnosticsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberSuppressDiagnosticsCodeFixProvider.cs index 6fb70bba..d7f3dac9 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberSuppressDiagnosticsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractNonSubstitutableMemberSuppressDiagnosticsCodeFixProvider.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal class AbstractNonSubstitutableMemberSuppressDiagnosticsCodeFixProvider : AbstractSuppressDiagnosticsCodeFixProvider { - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create( + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create( DiagnosticIdentifiers.NonVirtualSetupSpecification, DiagnosticIdentifiers.NonVirtualReceivedInOrderSetupSpecification); } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs index bb836a5a..480cc59c 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider.cs @@ -11,12 +11,12 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal abstract class AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider : CodeFixProvider { - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.PartialSubstituteForUnsupportedType); - public override async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var syntaxNode = root.FindNode(context.Span, getInnermostNodeForTie: true); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs index d79ce447..5c9cdadd 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractReceivedInReceivedInOrderCodeFixProvider.cs @@ -12,11 +12,11 @@ namespace NSubstitute.Analyzers.Shared.CodeFixProviders; internal abstract class AbstractReceivedInReceivedInOrderCodeFixProvider : CodeFixProvider { - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.ReceivedUsedInReceivedInOrder); + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.ReceivedUsedInReceivedInOrder); - public override Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var codeAction = CodeAction.Create( "Remove redundant Received checks", diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index 7b127dbc..ff7fe1f0 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -12,14 +12,14 @@ internal abstract class AbstractSubstituteForInternalMemberCodeFixProvider FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SubstituteForInternalMember); + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SubstituteForInternalMember); protected AbstractSubstituteForInternalMemberCodeFixProvider(ISubstituteProxyAnalysis substituteProxyAnalysis) { _substituteProxyAnalysis = substituteProxyAnalysis; } - public override async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index fd73d813..083cb7f3 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -21,12 +21,12 @@ protected AbstractSyncOverAsyncThrowsCodeFixProvider(ISubstitutionNodeFinder sub _substitutionNodeFinder = substitutionNodeFinder; } - public override ImmutableArray FixableDiagnosticIds { get; } = + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.SyncOverAsyncThrows); - public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - public override async Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs index 148f8e0b..15af18c2 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs @@ -19,7 +19,7 @@ protected AbstractAsyncReceivedInOrderCallbackAnalyzer( SupportedDiagnostics = ImmutableArray.Create(diagnosticDescriptorsProvider.AsyncCallbackUsedInReceivedInOrder); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected abstract SyntaxToken? GetAsyncToken(SyntaxNode node); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index cd004523..983238ee 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -34,9 +34,9 @@ protected AbstractCallInfoAnalyzer( DiagnosticDescriptorsProvider.CallInfoArgumentIsNotOutOrRef); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs index 5ce84e7d..50b377a0 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractConflictingArgumentAssignmentsAnalyzer.cs @@ -24,9 +24,9 @@ protected AbstractConflictingArgumentAssignmentsAnalyzer( SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.ConflictingArgumentAssignments); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs index 1b7a66fb..12bb5f90 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberAnalyzer.cs @@ -13,7 +13,7 @@ internal abstract class AbstractNonSubstitutableMemberAnalyzer : AbstractNonSubs private readonly Action _analyzeInvocationAction; - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected AbstractNonSubstitutableMemberAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -29,7 +29,7 @@ protected AbstractNonSubstitutableMemberAnalyzer( DiagnosticDescriptorsProvider.InternalSetupSpecification); } - protected override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } + protected sealed override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } protected sealed override void InitializeAnalyzer(AnalysisContext context) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs index 07651474..e306dbb7 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberArgumentMatcherAnalyzer.cs @@ -39,9 +39,9 @@ protected AbstractNonSubstitutableMemberArgumentMatcherAnalyzer( SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.NonSubstitutableMemberArgumentMatcherUsage); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs index 91c74dd7..32734968 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs @@ -11,7 +11,7 @@ internal abstract class AbstractNonSubstitutableMemberReceivedAnalyzer : Abstrac { private readonly Action _analyzeInvocationOperation; - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected AbstractNonSubstitutableMemberReceivedAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -25,9 +25,9 @@ protected AbstractNonSubstitutableMemberReceivedAnalyzer( NonVirtualSetupDescriptor = diagnosticDescriptorsProvider.NonVirtualReceivedSetupSpecification; } - protected override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } + protected sealed override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationOperation, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs index ff44e10a..659527e8 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedInOrderAnalyzer.cs @@ -10,7 +10,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; internal abstract class AbstractNonSubstitutableMemberReceivedInOrderAnalyzer : AbstractNonSubstitutableSetupAnalyzer { - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected ImmutableArray IgnoredAncestorPaths { get; } = ImmutableArray.Create( OperationKind.VariableDeclarator, @@ -35,7 +35,7 @@ protected AbstractNonSubstitutableMemberReceivedInOrderAnalyzer( DiagnosticDescriptorsProvider.NonVirtualReceivedInOrderSetupSpecification); } - protected override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } + protected sealed override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } protected sealed override void InitializeAnalyzer(AnalysisContext context) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs index 2d68ee7b..19a4b1bf 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberWhenAnalyzer.cs @@ -11,7 +11,7 @@ internal abstract class AbstractNonSubstitutableMemberWhenAnalyzer : AbstractNon { private readonly ISubstitutionNodeFinder _substitutionNodeFinder; - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } private readonly Action _analyzeInvocationAction; @@ -29,9 +29,9 @@ protected AbstractNonSubstitutableMemberWhenAnalyzer( NonVirtualSetupDescriptor = diagnosticDescriptorsProvider.NonVirtualWhenSetupSpecification; } - protected override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } + protected sealed override DiagnosticDescriptor NonVirtualSetupDescriptor { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs index 6b00ee9d..1328c089 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReEntrantSetupAnalyzer.cs @@ -13,7 +13,7 @@ internal abstract class AbstractReEntrantSetupAnalyzer : AbstractDiagnosticAnaly private readonly IReEntrantCallFinder _reEntrantCallFinder; private readonly Action _analyzeInvocationAction; - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected AbstractReEntrantSetupAnalyzer( IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider, @@ -25,7 +25,7 @@ protected AbstractReEntrantSetupAnalyzer( SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.ReEntrantSubstituteCall); } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs index 0bc241fe..e8124193 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractReceivedInReceivedInOrderAnalyzer.cs @@ -13,7 +13,7 @@ internal abstract class AbstractReceivedInReceivedInOrderAnalyzer : AbstractDiag private readonly ISubstitutionNodeFinder _substitutionNodeFinder; private readonly Action _analyzeInvocationAction; - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } protected AbstractReceivedInReceivedInOrderAnalyzer( ISubstitutionNodeFinder substitutionNodeFinder, @@ -25,7 +25,7 @@ protected AbstractReceivedInReceivedInOrderAnalyzer( SupportedDiagnostics = ImmutableArray.Create(diagnosticDescriptorsProvider.ReceivedUsedInReceivedInOrder); } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs index b3a78376..9d6ebf3c 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSubstituteAnalyzer.cs @@ -42,9 +42,9 @@ protected AbstractSubstituteAnalyzer( protected abstract SyntaxNode GetSubstituteInvocationExpressionSyntaxWithoutConstructorArguments(IInvocationOperation invocationOperation); - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs index 1fc0b2dd..2e9e0f74 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractSyncOverAsyncThrowsAnalyzer.cs @@ -22,9 +22,9 @@ protected AbstractSyncOverAsyncThrowsAnalyzer( _analyzeInvocationAction = AnalyzeInvocation; } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs index 9009c519..20add643 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractUnusedReceivedAnalyzer.cs @@ -18,12 +18,12 @@ protected AbstractUnusedReceivedAnalyzer(IDiagnosticDescriptorsProvider diagnost SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.UnusedReceived); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } private static readonly ImmutableHashSet PossibleParents = ImmutableHashSet.Create(OperationKind.PropertyReference, OperationKind.Invocation); - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs index 45bfdb5b..81668519 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractWithAnyArgsArgumentMatcherAnalyzer.cs @@ -27,9 +27,9 @@ protected AbstractWithAnyArgsArgumentMatcherAnalyzer( SupportedDiagnostics = ImmutableArray.Create(DiagnosticDescriptorsProvider.WithAnyArgsArgumentMatcherUsage); } - public override ImmutableArray SupportedDiagnostics { get; } + public sealed override ImmutableArray SupportedDiagnostics { get; } - protected override void InitializeAnalyzer(AnalysisContext context) + protected sealed override void InitializeAnalyzer(AnalysisContext context) { context.RegisterOperationAction(_analyzeInvocationAction, OperationKind.Invocation); } diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs index 72e7eeb6..18b08c6a 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/CallInfoFinder.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal class CallInfoFinder : ICallInfoFinder +internal sealed class CallInfoFinder : ICallInfoFinder { public static CallInfoFinder Instance { get; } = new(); @@ -118,7 +118,7 @@ private static IParameterSymbol GetCallInfoParameterSymbol(IOperation operation) }; } - private class CallInfoVisitor : OperationWalker + private sealed class CallInfoVisitor : OperationWalker { public List ArgAtInvocations { get; } = new(); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs index 961124fa..55bbd1aa 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/ReEntrantCallFinder.cs @@ -145,7 +145,7 @@ private IEnumerable GetReEntrantSymbols(Compilation compilation, IIn return reentryVisitor.InvocationOperations; } - private class ReEntrantCallVisitor : OperationWalker + private sealed class ReEntrantCallVisitor : OperationWalker { private readonly Compilation _compilation; private readonly HashSet _visitedOperations = new(); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs index c637f482..4708906f 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteConstructorAnalysis.cs @@ -6,7 +6,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal class SubstituteConstructorAnalysis : ISubstituteConstructorAnalysis +internal sealed class SubstituteConstructorAnalysis : ISubstituteConstructorAnalysis { public static SubstituteConstructorAnalysis Instance { get; } = new(); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs index c491d805..d808d32f 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstituteProxyAnalysis.cs @@ -5,7 +5,7 @@ namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; -internal class SubstituteProxyAnalysis : ISubstituteProxyAnalysis +internal sealed class SubstituteProxyAnalysis : ISubstituteProxyAnalysis { public static SubstituteProxyAnalysis Instance { get; } = new(); diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs index 83b80a85..10639874 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/SubstitutionNodeFinder.cs @@ -117,7 +117,7 @@ private static IEnumerable GetBaseTypesAndThis(ITypeSymbol type) return FindForStandardExpression(parentInvocationOperation); } - private class WhenVisitor : OperationWalker + private sealed class WhenVisitor : OperationWalker { private readonly Compilation _compilation; private readonly IInvocationOperation _whenInvocationOperation; diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs index c84c7526..a6100ae1 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/SubstituteConstructorMatcher.cs @@ -4,7 +4,7 @@ namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; -internal class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher +internal sealed class SubstituteConstructorMatcher : AbstractSubstituteConstructorMatcher { public static SubstituteConstructorMatcher Instance { get; } = new(); From 5dacece63bf46fe5ecc2ca6c16213a5b86a5a315 Mon Sep 17 00:00:00 2001 From: tpodolak Date: Sun, 2 Oct 2022 22:01:34 +0200 Subject: [PATCH 35/35] GH-153 - removing redundant code --- .../DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs | 1 - .../AbstractNonSubstitutableMemberReceivedAnalyzer.cs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs index 983238ee..5e316887 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractCallInfoAnalyzer.cs @@ -303,7 +303,6 @@ private IndexerInfo GetIndexerInfo(IOperation indexerOperation) { ISymbol info = indexerOperation switch { - IInvocationOperation inv => inv.TargetMethod, IArrayElementReferenceOperation x => x.Type, _ => null }; diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs index 32734968..cfd25623 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonSubstitutableMemberReceivedAnalyzer.cs @@ -36,11 +36,6 @@ private void AnalyzeInvocation(OperationAnalysisContext syntaxNodeContext) { var invocationOperation = (IInvocationOperation)syntaxNodeContext.Operation; - if (invocationOperation.Parent == null) - { - return; - } - if (invocationOperation.TargetMethod.IsReceivedLikeMethod() == false) { return;