Skip to content

Commit

Permalink
Merge pull request #193 from nsubstitute/GH-153-operation-api-next-st…
Browse files Browse the repository at this point in the history
…age-with-args

Gh 153 - handle out of order parameters when analyzing NSubstitute usages
  • Loading branch information
tpodolak authored Nov 17, 2022
2 parents 45a6488 + 5dacece commit d001bdb
Show file tree
Hide file tree
Showing 229 changed files with 4,785 additions and 4,158 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="$(SolutionDir)/StyleCop.json" />
<AdditionalFiles Include="$(SolutionDir)/StyleCop.json"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all"/>
</ItemGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace NSubstitute.Analyzers.Benchmarks.CSharp;

public class CSharpDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks
public sealed class CSharpDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks
{
protected override AnalyzerBenchmark CallInfoAnalyzerBenchmark { get; }

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

namespace NSubstitute.Analyzers.Benchmarks.CSharp;

public class CSharpSolutionLoader : AbstractSolutionLoader
public sealed class CSharpSolutionLoader : AbstractSolutionLoader
{
protected override string DocumentFileExtension { get; } = ".cs";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ private static HashSet<Assembly> RecursiveReferencedAssemblies(
Assembly assembly,
HashSet<Assembly> recursiveAssemblies = null)
{
recursiveAssemblies = recursiveAssemblies ?? new HashSet<Assembly>();
recursiveAssemblies ??= new HashSet<Assembly>();
if (recursiveAssemblies.Add(assembly))
{
foreach (AssemblyName referencedAssembly in assembly.GetReferencedAssemblies())
foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
{
Assembly result;
if (TryGetOrLoad(referencedAssembly, out result))
Expand All @@ -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()))}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace NSubstitute.Analyzers.Benchmarks.Shared;

public class AnalyzerBenchmark
public sealed class AnalyzerBenchmark
{
private readonly BenchmarkAnalyzer _benchmarkAnalyzer;
private readonly Solution _solution;
Expand Down Expand Up @@ -188,29 +188,29 @@ public void Run()
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
private class BenchmarkAnalyzer : DiagnosticAnalyzer
{
internal List<ContextAndAction<SyntaxNodeAnalysisContext>> SyntaxNodeActions { get; } = new List<ContextAndAction<SyntaxNodeAnalysisContext>>();
internal List<ContextAndAction<SyntaxNodeAnalysisContext>> SyntaxNodeActions { get; } = new();

internal List<ContextAndAction<CompilationStartAnalysisContext>> CompilationStartActions { get; } = new List<ContextAndAction<CompilationStartAnalysisContext>>();
internal List<ContextAndAction<CompilationStartAnalysisContext>> CompilationStartActions { get; } = new();

internal List<ContextAndAction<CompilationAnalysisContext>> CompilationEndActions { get; } = new List<ContextAndAction<CompilationAnalysisContext>>();
internal List<ContextAndAction<CompilationAnalysisContext>> CompilationEndActions { get; } = new();

internal List<ContextAndAction<CompilationAnalysisContext>> CompilationActions { get; } = new List<ContextAndAction<CompilationAnalysisContext>>();
internal List<ContextAndAction<CompilationAnalysisContext>> CompilationActions { get; } = new();

internal List<ContextAndAction<SemanticModelAnalysisContext>> SemanticModelActions { get; } = new List<ContextAndAction<SemanticModelAnalysisContext>>();
internal List<ContextAndAction<SemanticModelAnalysisContext>> SemanticModelActions { get; } = new();

internal List<ContextAndAction<SymbolAnalysisContext>> SymbolActions { get; } = new List<ContextAndAction<SymbolAnalysisContext>>();
internal List<ContextAndAction<SymbolAnalysisContext>> SymbolActions { get; } = new();

internal List<IContextAndAction> CodeBlockStartActions { get; } = new List<IContextAndAction>();
internal List<IContextAndAction> CodeBlockStartActions { get; } = new();

internal List<ContextAndAction<CodeBlockAnalysisContext>> CodeBlockActions { get; } = new List<ContextAndAction<CodeBlockAnalysisContext>>();
internal List<ContextAndAction<CodeBlockAnalysisContext>> CodeBlockActions { get; } = new();

internal List<ContextAndAction<SyntaxTreeAnalysisContext>> SyntaxTreeActions { get; } = new List<ContextAndAction<SyntaxTreeAnalysisContext>>();
internal List<ContextAndAction<SyntaxTreeAnalysisContext>> SyntaxTreeActions { get; } = new();

internal List<ContextAndAction<OperationAnalysisContext>> OperationActions { get; } = new List<ContextAndAction<OperationAnalysisContext>>();
internal List<ContextAndAction<OperationAnalysisContext>> OperationActions { get; } = new();

internal List<ContextAndAction<OperationBlockAnalysisContext>> OperationBlockActions { get; } = new List<ContextAndAction<OperationBlockAnalysisContext>>();
internal List<ContextAndAction<OperationBlockAnalysisContext>> OperationBlockActions { get; } = new();

internal List<ContextAndAction<OperationBlockStartAnalysisContext>> OperationBlockStartActions { get; } = new List<ContextAndAction<OperationBlockStartAnalysisContext>>();
internal List<ContextAndAction<OperationBlockStartAnalysisContext>> OperationBlockStartActions { get; } = new();

private readonly DiagnosticAnalyzer _inner;

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

namespace NSubstitute.Analyzers.Benchmarks.VisualBasic;

public class VisualBasicDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks
public sealed class VisualBasicDiagnosticAnalyzersBenchmarks : AbstractDiagnosticAnalyzersBenchmarks
{
protected override AnalyzerBenchmark CallInfoAnalyzerBenchmark { get; }

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

namespace NSubstitute.Analyzers.Benchmarks.VisualBasic;

public class VisualBasicSolutionLoader : AbstractSolutionLoader
public sealed class VisualBasicSolutionLoader : AbstractSolutionLoader
{
protected override string DocumentFileExtension { get; } = ".vb";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<InvocationExpressionSyntax>
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 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.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)));
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
Expand All @@ -12,18 +13,27 @@ internal sealed class InternalSetupSpecificationCodeFixProvider : AbstractIntern
{
protected override string ReplaceModifierCodeFixTitle { get; } = "Replace internal with public modifier";

protected override Task<Document> AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility)
protected override Task<Document> 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<Document> ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility)
protected override Task<Document> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -10,5 +8,4 @@ namespace NSubstitute.Analyzers.CSharp.CodeFixProviders;
internal sealed class NonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider
: AbstractNonSubstitutableMemberArgumentMatcherSuppressDiagnosticsCodeFixProvider
{
protected override ImmutableHashSet<int> MaybeAllowedArgMatcherAncestors { get; } = NonSubstitutableMemberArgumentMatcherAnalyzer.MaybeAllowedAncestors;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<InvocationExpressionSyntax, GenericNameSyntax, IdentifierNameSyntax, SimpleNameSyntax>
internal sealed class PartialSubstituteUsedForUnsupportedTypeCodeFixProvider : AbstractPartialSubstituteUsedForUnsupportedTypeCodeFixProvider
{
protected override TInnerNameSyntax GetNameSyntax<TInnerNameSyntax>(InvocationExpressionSyntax methodInvocationNode)
protected override SyntaxNode UpdateInvocationExpression(IInvocationOperation invocationOperation, string identifierName)
{
var memberAccess = (MemberAccessExpressionSyntax)methodInvocationNode.Expression;
return (TInnerNameSyntax)memberAccess.Name;
}

protected override TInnerNameSyntax GetUpdatedNameSyntax<TInnerNameSyntax>(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))));
}
}
Loading

0 comments on commit d001bdb

Please sign in to comment.