Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:nsubstitute/NSubstitute.Analyzers into
Browse files Browse the repository at this point in the history
GH-35-arg-matcher
  • Loading branch information
tpodolak committed Aug 24, 2019
2 parents 79a45f5 + 2e23d39 commit 7c82bdb
Show file tree
Hide file tree
Showing 72 changed files with 794 additions and 535 deletions.
31 changes: 31 additions & 0 deletions NSubstitute.Analyzers.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ ProjectSection(SolutionItems) = preProject
documentation\rules\NS1003.md = documentation\rules\NS1003.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{93C6B41F-4074-462E-A36B-E0C715A5A13C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSubstitute.Analyzers.Benchmarks", "benchmarks\NSubstitute.Analyzers.Benchmarks\NSubstitute.Analyzers.Benchmarks.csproj", "{1B323827-5E80-4805-9998-D445DFB2EB14}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSubstitute.Analyzers.Benchmarks.Source.CSharp", "benchmarks\NSubstitute.Analyzers.Benchmarks.Source.CSharp\NSubstitute.Analyzers.Benchmarks.Source.CSharp.csproj", "{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "NSubstitute.Analyzers.Benchmarks.Source.VisualBasic", "benchmarks\NSubstitute.Analyzers.Benchmarks.Source.VisualBasic\NSubstitute.Analyzers.Benchmarks.Source.VisualBasic.vbproj", "{A938D963-AF53-46FD-93E9-729BD0552258}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSubstitute.Analyzers.Tests.Benchmarks", "tests\NSubstitute.Analyzers.Tests.Benchmarks\NSubstitute.Analyzers.Tests.Benchmarks.csproj", "{95DE6153-B008-4481-B074-032AD42F8E42}"
EndProject

Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -85,6 +96,22 @@ Global
{0B098301-16AA-401B-ACAC-3D81189C18C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B098301-16AA-401B-ACAC-3D81189C18C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B098301-16AA-401B-ACAC-3D81189C18C6}.Release|Any CPU.Build.0 = Release|Any CPU
{1B323827-5E80-4805-9998-D445DFB2EB14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B323827-5E80-4805-9998-D445DFB2EB14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B323827-5E80-4805-9998-D445DFB2EB14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B323827-5E80-4805-9998-D445DFB2EB14}.Release|Any CPU.Build.0 = Release|Any CPU
{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16}.Release|Any CPU.Build.0 = Release|Any CPU
{A938D963-AF53-46FD-93E9-729BD0552258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A938D963-AF53-46FD-93E9-729BD0552258}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A938D963-AF53-46FD-93E9-729BD0552258}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A938D963-AF53-46FD-93E9-729BD0552258}.Release|Any CPU.Build.0 = Release|Any CPU
{95DE6153-B008-4481-B074-032AD42F8E42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95DE6153-B008-4481-B074-032AD42F8E42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95DE6153-B008-4481-B074-032AD42F8E42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95DE6153-B008-4481-B074-032AD42F8E42}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2B7BF4D2-4964-4674-9268-70AE5A3C98DB} = {FB46CD9F-6E27-4767-AD1E-8C21CD08F993}
Expand All @@ -95,5 +122,9 @@ Global
{00A000B8-B887-4216-92B2-E810616CE7A8} = {0ED2F2A2-CF6E-4EED-8166-F22B5D7631F4}
{4DF03310-98B3-450E-90FE-2EF423A6CC59} = {FB46CD9F-6E27-4767-AD1E-8C21CD08F993}
{0B098301-16AA-401B-ACAC-3D81189C18C6} = {FB46CD9F-6E27-4767-AD1E-8C21CD08F993}
{1B323827-5E80-4805-9998-D445DFB2EB14} = {93C6B41F-4074-462E-A36B-E0C715A5A13C}
{A7F6CAFC-F7E1-4FA8-8360-9BEC71255E16} = {93C6B41F-4074-462E-A36B-E0C715A5A13C}
{A938D963-AF53-46FD-93E9-729BD0552258} = {93C6B41F-4074-462E-A36B-E0C715A5A13C}
{95DE6153-B008-4481-B074-032AD42F8E42} = {0ED2F2A2-CF6E-4EED-8166-F22B5D7631F4}
EndGlobalSection
EndGlobal
19 changes: 14 additions & 5 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
### 1.0.10 (5 June 2019)

- [#103](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/103) - Enable concurrent execution for every analyzer
- [#93](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/93) - NS4000 Unexpected warning in foreach loop

### 1.0.9 (12 April 2019)

- [#91](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/91) - Erroneous NS1002 errors for Arg.Any calls

### 1.0.8 (08 April 2019)

- [#89](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/89) NS1002 doesn't detect non-virtual calls from base class
- [#87](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/87) NS1002 highlights wrong member
- [#78](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/78) Update documentation so as it includes information about min supported Visual Studio version
- [#76](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/76) Analyze callInfo usages for Do method
- [#62](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/62) Detecting conflicting out/ref arguments
- [#89](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/89) - NS1002 doesn't detect non-virtual calls from base class
- [#87](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/87) - NS1002 highlights wrong member
- [#78](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/78) - Update documentation so as it includes information about min supported Visual Studio version
- [#76](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/76) - Analyze callInfo usages for Do method
- [#62](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/62) - Detecting conflicting out/ref arguments

### 1.0.7 (15 March 2019)

Expand Down
4 changes: 4 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ for:
- image: Ubuntu
test: off
build_script:
- sudo mv global.json _global.json #workaround for missing AppVeyor images
- dotnet new globaljson --sdk-version 2.2.401
- cd build
- chmod +xxx ./build.sh
- ./build.sh --target="AppVeyor" --configuration=Release --UploadCoverageReport=False
Expand All @@ -20,6 +22,8 @@ for:
- image: Visual Studio 2017
test: off
build_script:
- move global.json _global.json #workaround for missing AppVeyor images
- dotnet new globaljson --sdk-version 2.2.301
- cd Build
- ps: >-
.\build.ps1 --target="AppVeyor" --configuration=Release --UploadCoverageReport=True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public void NS5001_ArgumentMatcherUsedWithoutSpecifyingCall()

substitute.ObjectReturningMethodWithArguments(Arg.Is(0), Arg.Is(0), Arg.Is(0m));
substitute.ObjectReturningMethodWithArguments(Arg.Compat.Is(0), Arg.Compat.Is(0), Arg.Compat.Is(0m));

// correct usages
Received.InOrder(() =>
{
Expand Down
1 change: 1 addition & 0 deletions build/build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#tool "nuget:https://www.nuget.org/api/v2?package=ReportGenerator&version=4.0.4"
#addin "nuget:https://www.nuget.org/api/v2?package=Cake.Incubator&version=4.0.1"
#addin "nuget:https://www.nuget.org/api/v2?package=Newtonsoft.Json&version=9.0.1"
#addin "nuget:https://www.nuget.org/api/v2?package=semver.core&version=2.0.0"

using Newtonsoft.Json.Linq;
using System.Net.Http;
Expand Down
2 changes: 1 addition & 1 deletion build/releasenotes.cake
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ReleaseNotes
{
var releaseNotes = context.ParseAllReleaseNotes(paths.Files.AllReleaseNotes);
return releaseNotes.Select(note => new ReleaseNotes(note))
.OrderByDescending(note => note.SemVersion)
.OrderByDescending(note => Semver.SemVersion.Parse(note.SemVersion))
.ToList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace NSubstitute.Analyzers.CSharp.CodeFixProviders
{
[ExportCodeFixProvider(LanguageNames.CSharp)]
internal class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider<InvocationExpressionSyntax>
internal sealed class ConstructorArgumentsForInterfaceCodeFixProvider : AbstractConstructorArgumentsForInterfaceCodeFixProvider<InvocationExpressionSyntax>
{
protected override InvocationExpressionSyntax GetInvocationExpressionSyntaxWithEmptyArgumentList(InvocationExpressionSyntax invocationExpressionSyntax)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace NSubstitute.Analyzers.CSharp.CodeFixProviders
{
[ExportCodeFixProvider(LanguageNames.CSharp)]
internal class InternalSetupSpecificationCodeFixProvider : AbstractInternalSetupSpecificationCodeFixProvider<CompilationUnitSyntax>
internal sealed class InternalSetupSpecificationCodeFixProvider : AbstractInternalSetupSpecificationCodeFixProvider<CompilationUnitSyntax>
{
protected override string ReplaceModifierCodeFixTitle { get; } = "Replace internal with public modifier";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace NSubstitute.Analyzers.CSharp.CodeFixProviders
{
[ExportCodeFixProvider(LanguageNames.CSharp)]
internal class NonVirtualSetupSuppressDiagnosticsCodeFixProvider : AbstractNonVirtualSetupSuppressDiagnosticsCodeFixProvider
internal sealed class NonVirtualSetupSuppressDiagnosticsCodeFixProvider : AbstractNonVirtualSetupSuppressDiagnosticsCodeFixProvider
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace NSubstitute.Analyzers.CSharp.CodeFixProviders
{
[ExportCodeFixProvider(LanguageNames.CSharp)]
internal class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider<InvocationExpressionSyntax, GenericNameSyntax, IdentifierNameSyntax, SimpleNameSyntax>
internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider<InvocationExpressionSyntax, GenericNameSyntax, IdentifierNameSyntax, SimpleNameSyntax>
{
protected override TInnerNameSyntax GetNameSyntax<TInnerNameSyntax>(InvocationExpressionSyntax methodInvocationNode)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
namespace NSubstitute.Analyzers.CSharp.CodeFixProviders
{
[ExportCodeFixProvider(LanguageNames.CSharp)]
internal class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider<InvocationExpressionSyntax, ExpressionSyntax, CompilationUnitSyntax>
internal sealed class SubstituteForInternalMemberCodeFixProvider : AbstractSubstituteForInternalMemberCodeFixProvider<InvocationExpressionSyntax, ExpressionSyntax, CompilationUnitSyntax>
{
protected override AbstractSubstituteProxyAnalysis<InvocationExpressionSyntax, ExpressionSyntax> GetSubstituteProxyAnalysis()
public SubstituteForInternalMemberCodeFixProvider()
: base(SubstituteProxyAnalysis.Instance)
{
return new SubstituteProxyAnalysis();
}

protected override void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CallInfoAnalyzer : AbstractCallInfoAnalyzer<SyntaxKind, InvocationExpressionSyntax, ExpressionSyntax, ElementAccessExpressionSyntax>
internal sealed class CallInfoAnalyzer : AbstractCallInfoAnalyzer<SyntaxKind, InvocationExpressionSyntax, ExpressionSyntax, ElementAccessExpressionSyntax>
{
public CallInfoAnalyzer()
: base(new DiagnosticDescriptorsProvider(), new CallInfoCallFinder(), new SubstitutionNodeFinder())
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance, SubstitutionNodeFinder.Instance)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
internal class CallInfoCallFinder : ICallInfoFinder<InvocationExpressionSyntax, ElementAccessExpressionSyntax>
{
public static CallInfoCallFinder Instance { get; } = new CallInfoCallFinder();

private CallInfoCallFinder()
{
}

public CallInfoContext<InvocationExpressionSyntax, ElementAccessExpressionSyntax> GetCallInfoContext(SemanticModel semanticModel, SyntaxNode syntaxNode)
{
var visitor = new CallInfoVisitor(semanticModel);
Expand Down Expand Up @@ -65,6 +71,86 @@ public override void VisitElementAccessExpression(ElementAccessExpressionSyntax

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)
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer<SyntaxKind, InvocationExpressionSyntax, ExpressionSyntax, ElementAccessExpressionSyntax>
internal sealed class ConflictingArgumentAssignmentsAnalyzer : AbstractConflictingArgumentAssignmentsAnalyzer<SyntaxKind, InvocationExpressionSyntax, ExpressionSyntax, ElementAccessExpressionSyntax>
{
public ConflictingArgumentAssignmentsAnalyzer()
: base(new DiagnosticDescriptorsProvider(), new CallInfoCallFinder())
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, CallInfoCallFinder.Instance)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
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
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer<SyntaxKind, MemberAccessExpressionSyntax, InvocationExpressionSyntax>
internal sealed class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAnalyzer<SyntaxKind, InvocationExpressionSyntax>
{
protected override SyntaxKind SimpleMemberAccessExpressionKind { get; } = SyntaxKind.SimpleMemberAccessExpression;

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

protected override ImmutableHashSet<Type> KnownNonVirtualSyntaxTypes { get; } = ImmutableHashSet.Create(
protected override ImmutableHashSet<Type> KnownNonVirtualSyntaxKinds { get; } = ImmutableHashSet.Create(
typeof(LiteralExpressionSyntax));

protected override ImmutableHashSet<int> SupportedMemberAccesses { get; } = ImmutableHashSet.Create(
Expand All @@ -30,18 +30,8 @@ internal class NonSubstitutableMemberAnalyzer : AbstractNonSubstitutableMemberAn
(int)SyntaxKind.StringLiteralExpression);

public NonSubstitutableMemberAnalyzer()
: base(new DiagnosticDescriptorsProvider())
{
}

protected override SyntaxNode GetArgument(InvocationExpressionSyntax invocationExpressionSyntax)
{
return invocationExpressionSyntax.ArgumentList.Arguments.FirstOrDefault()?.DescendantNodes().FirstOrDefault();
}

protected override string GetAccessedMemberName(MemberAccessExpressionSyntax memberAccessExpressionSyntax)
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance)
{
return memberAccessExpressionSyntax.Name.Identifier.Text;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer<SyntaxKind, MemberAccessExpressionSyntax>
internal sealed class NonSubstitutableMemberReceivedAnalyzer : AbstractNonSubstitutableMemberReceivedAnalyzer<SyntaxKind, MemberAccessExpressionSyntax>
{
protected override ImmutableArray<Parent> PossibleParents { get; } = ImmutableArray.Create(
Parent.Create<MemberAccessExpressionSyntax>(),
Parent.Create<InvocationExpressionSyntax>(),
Parent.Create<ElementAccessExpressionSyntax>());
protected override ImmutableHashSet<int> PossibleParentsRawKinds { get; } = ImmutableHashSet.Create(
(int)SyntaxKind.SimpleMemberAccessExpression,
(int)SyntaxKind.InvocationExpression,
(int)SyntaxKind.ElementAccessExpression);

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

public NonSubstitutableMemberReceivedAnalyzer()
: base(new DiagnosticDescriptorsProvider())
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance)
{
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer<SyntaxKind, InvocationExpressionSyntax, MemberAccessExpressionSyntax>
internal sealed class NonSubstitutableMemberWhenAnalyzer : AbstractNonSubstitutableMemberWhenAnalyzer<SyntaxKind, InvocationExpressionSyntax, MemberAccessExpressionSyntax>
{
public NonSubstitutableMemberWhenAnalyzer()
: base(new DiagnosticDescriptorsProvider(), new SubstitutionNodeFinder())
: base(NSubstitute.Analyzers.CSharp.DiagnosticDescriptorsProvider.Instance, SubstitutionNodeFinder.Instance)
{
}

Expand Down
Loading

0 comments on commit 7c82bdb

Please sign in to comment.