Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split off CodeFixes from analyzer #831

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ var PACKAGE_DIR = PROJECT_DIR + "package/" + configuration;

var ANALYZERS_TESTS_OUTPUT_DIR = SRC_DIR + "nunit.analyzers.tests/bin/";
var ANALYZERS_OUTPUT_DIR = SRC_DIR + "nunit.analyzers/bin/";
var CODEFIXES_OUTPUT_DIR = SRC_DIR + "nunit.analyzers.codefixes/bin/";

// Solution
var SOLUTION_FILE = PROJECT_DIR + "src/nunit.analyzers.sln";

// Projects
var ANALYZER_PROJECT = SRC_DIR + "nunit.analyzers/nunit.analyzers.csproj";
var CODEFIXES_PROJECT = SRC_DIR + "nunit.analyzers.codefixes/nunit.analyzers.codefixes.csproj";
var TEST_PROJECT = SRC_DIR + "nunit.analyzers.tests/nunit.analyzers.tests.csproj";

// Package sources for nuget restore
Expand Down Expand Up @@ -103,6 +105,7 @@ Task("Clean")
.Does(() =>
{
CleanDirectory(ANALYZERS_TESTS_OUTPUT_DIR);
CleanDirectory(CODEFIXES_OUTPUT_DIR);
CleanDirectory(ANALYZERS_OUTPUT_DIR);
});

Expand All @@ -128,7 +131,7 @@ Task("Build")
.IsDependentOn("RestorePackages")
.Does(() =>
{
DotNetBuild(ANALYZER_PROJECT, new DotNetBuildSettings
var buildSettings = new DotNetBuildSettings
{
Configuration = configuration,
Verbosity = DotNetVerbosity.Minimal,
Expand All @@ -138,7 +141,9 @@ Task("Build")
Version = packageVersion,
FileVersion = packageVersion,
}
});
};
DotNetBuild(ANALYZER_PROJECT, buildSettings);
DotNetBuild(CODEFIXES_PROJECT, buildSettings);
});

//////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -192,7 +197,7 @@ Task("Pack")
.IsDependentOn("Build")
.Does(() =>
{
NuGetPack("./src/nunit.analyzers/nunit.analyzers.nuspec", new NuGetPackSettings()
NuGetPack("./src/nunit.analyzers.nuspec", new NuGetPackSettings()
{
Version = packageVersionString,
OutputDirectory = PACKAGE_DIR + "/" + targetFramework,
Expand Down
17 changes: 14 additions & 3 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<Company>NUnit Project</Company>
<Product>NUnit Analyzers</Product>
<Copyright>Copyright © 2018-2025 NUnit project</Copyright>
<!-- https://docs.microsoft.com/en-us/nuget/reference/nuspec#developmentdependency -->
<developmentDependency>true</developmentDependency>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -14,16 +16,24 @@
<LangVersion>preview</LangVersion>
<!-- Counter intuitive, but this only enabled the pre-shipped analyzer, we configure them below -->
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<AnalysisLevel>5</AnalysisLevel>
<NoWarn>$(NoWarn);CA1014</NoWarn>
<AnalysisLevel>8</AnalysisLevel>
<NoWarn>$(NoWarn);CA1014;CS1591</NoWarn>
</PropertyGroup>

<PropertyGroup>
<!--
No we shouldn't create documentation files for analyzers, but it is needed
to enable IDE0005 (Remove unnecessary usings/imports) on build (https://github.com/dotnet/roslyn/issues/41640)
-->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.556" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="3.11.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="4.10.0" PrivateAssets="all" />
<PackageReference Include="CSharpIsNullAnalyzer" Version="0.1.593" PrivateAssets="all" />
</ItemGroup>

Expand All @@ -39,6 +49,7 @@

<ItemGroup>
<InternalsVisibleTo Include="nunit.analyzers.tests" />
<InternalsVisibleTo Include="nunit.analyzers.codefixes" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ protected virtual (ExpressionSyntax? actual, ExpressionSyntax? constraintExpress
{
actualArgumentWithCorrectTrivia,
constraintArgumentWithCorrectTrivia
}.Union(remainingArguments);
}.Concat(remainingArguments);

var newArgumentsList = assertNode.ArgumentList.WithArguments(newArguments);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public static ArgumentListSyntax WithArguments(
this ArgumentListSyntax @this,
IEnumerable<ArgumentSyntax> newArguments)
{
using var enumerator = newArguments.GetEnumerator();
if (!enumerator.MoveNext())
return @this;

var originalArguments = @this.Arguments;
var originalSeparators = originalArguments.GetSeparators().ToArray();

Expand All @@ -29,10 +33,12 @@ public static ArgumentListSyntax WithArguments(
// or any of the original separators had a trailing newline.
var shouldAddTrailingNewlineAfterComma = TryGetFirstEndOfLineTrivia(@this.OpenParenToken, originalSeparators, out var trailingTrivia);

var nodesAndTokens = new List<SyntaxNodeOrToken> { newArguments.First() };
var nodesAndTokens = new List<SyntaxNodeOrToken> { enumerator.Current };

foreach (var newArgument in newArguments.Skip(1))
while (enumerator.MoveNext())
{
var newArgument = enumerator.Current;

// If argument is not replaced - take original separator. Otherwise - comma
var oldIndex = originalArguments.IndexOf(newArgument);
var separator = originalSeparators.ElementAtOrDefault(oldIndex - 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ internal static class CodeFixHelper
/// </summary>
/// <param name="arguments">The arguments passed to the 'Assert' method. </param>
/// <param name="minimumNumberOfArguments">The argument needed for the actual method, any more are assumed messages.</param>
/// <param name="argsIsArray">The params args is passed as an array instead of individual parameters.</param>
public static void UpdateStringFormatToFormattableString(List<ArgumentSyntax> arguments, int minimumNumberOfArguments, bool argsIsArray)
{
// If only 1 extra argument is passed, it must be a non-formattable message.
Expand Down
15 changes: 15 additions & 0 deletions src/nunit.analyzers.codefixes/nunit.analyzers.codefixes.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>NUnit.Analyzers</RootNamespace>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../nunit.analyzers/nunit.analyzers.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ Version 3.0 and upwards works in Visual Studio 2019 (version 16.3) or newer and
</metadata>
<!-- The convention for analyzers is to put language agnostic dlls in analyzers\portable50 and language specific analyzers in either analyzers\portable50\cs or analyzers\portable50\vb -->
<files>
<file src="bin\$Configuration$\$TargetFramework$\nunit.analyzers.dll" target="analyzers\dotnet\cs\" />
<file src="nunit.analyzers\bin\$Configuration$\$TargetFramework$\nunit.analyzers.dll" target="analyzers\dotnet\cs\" />
<file src="nunit.analyzers.codefixes\bin\$Configuration$\$TargetFramework$\nunit.analyzers.codefixes.dll" target="analyzers\dotnet\cs\" />
<file src="tools\*.ps1" target="tools\" />
<file src="..\..\license.txt" target="" />
<file src="..\..\nunit_256.png" target="images" />
<file src="..\..\README.md" target="docs" />
<file src="..\license.txt" target="" />
<file src="..\nunit_256.png" target="images" />
<file src="..\README.md" target="docs" />
</files>
</package>
6 changes: 6 additions & 0 deletions src/nunit.analyzers.sln
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\global.json = ..\global.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nunit.analyzers.codefixes", "nunit.analyzers.codefixes\nunit.analyzers.codefixes.csproj", "{E77F7B58-BD1F-48F6-BB6A-E55CCE12C714}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -126,6 +128,10 @@ Global
{070974CB-B483-4347-BA5A-53ED977E639C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{070974CB-B483-4347-BA5A-53ED977E639C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{070974CB-B483-4347-BA5A-53ED977E639C}.Release|Any CPU.Build.0 = Release|Any CPU
{E77F7B58-BD1F-48F6-BB6A-E55CCE12C714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E77F7B58-BD1F-48F6-BB6A-E55CCE12C714}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E77F7B58-BD1F-48F6-BB6A-E55CCE12C714}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E77F7B58-BD1F-48F6-BB6A-E55CCE12C714}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
14 changes: 14 additions & 0 deletions src/nunit.analyzers.tests/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# C# files
[*.cs]

# Not relevant for single execution unit tests

# CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA1861.severity = none

# CA1859: Use concrete types when possible for improved performance
dotnet_diagnostic.CA1859.severity = none

# CA1863 Cache a 'CompositeFormat' for repeated use in this formatting operation
dotnet_diagnostic.CA1863.severity = none

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using Gu.Roslyn.Asserts;
using Microsoft.CodeAnalysis.Diagnostics;
using NUnit.Analyzers.ClassicModelAssertUsage;
using NUnit.Analyzers.CollectionAssertUsage;
using NUnit.Analyzers.Constants;
using NUnit.Framework;
Expand Down
49 changes: 0 additions & 49 deletions src/nunit.analyzers.tests/DefaultEnabledAnalyzer.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ public void OneTimeSetUp()
Assembly netAnalyzerAssembly = Assembly.LoadFrom(netAnalyzersPath);
Type analyzerType = netAnalyzerAssembly.GetType("Microsoft.CodeQuality.CSharp.Analyzers.Maintainability.CSharpAvoidUninstantiatedInternalClasses", true)!;
this.analyzer = (DiagnosticAnalyzer)Activator.CreateInstance(analyzerType)!;

this.analyzer = new DefaultEnabledAnalyzer(this.analyzer);
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public void OneTimeSetUp()
Assembly netAnalyzerAssembly = Assembly.LoadFrom(netAnalyzersPath);
Type analyzerType = netAnalyzerAssembly.GetType("Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer", true)!;
this.analyzer = (DiagnosticAnalyzer)Activator.CreateInstance(analyzerType)!;

this.analyzer = new DefaultEnabledAnalyzer(this.analyzer);
}

[Test]
Expand Down
3 changes: 2 additions & 1 deletion src/nunit.analyzers.tests/SetUpFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public void SetDefaults()
.WithMetadataReferences(MetadataReferences.Transitive(typeof(Assert), typeof(ClassicAssert)))
.WithParseOption(new CSharpParseOptions(LanguageVersion.Preview).WithPreprocessorSymbols("NUNIT4"));
#else
.WithMetadataReferences(MetadataReferences.Transitive(typeof(Assert)));
.WithMetadataReferences(MetadataReferences.Transitive(typeof(Assert)))
.WithParseOption(new CSharpParseOptions(LanguageVersion.Preview).WithPreprocessorSymbols("NUNIT3"));
#endif
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/nunit.analyzers.tests/TestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ internal static async Task SuppressedOrNot(DiagnosticAnalyzer analyzer, Diagnost
Assert.That(suppressor.SupportedSuppressions.Select(x => x.SuppressedDiagnosticId), Does.Contain(id));

settings ??= Settings.Default;
settings = settings.WithCompilationOptions(Settings.Default.CompilationOptions.WithWarningOrError(analyzer.SupportedDiagnostics));
settings = settings.WithCompilationOptions(Settings.Default.CompilationOptions.WithWarningOrError(analyzer.SupportedDiagnostics))
.WithAnalyzerConfig($"dotnet_diagnostic.{id}.severity = error");

Compilation compilation = CreateCompilation(code, settings);

Expand Down
3 changes: 2 additions & 1 deletion src/nunit.analyzers.tests/nunit.analyzers.tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Gu.Roslyn.Asserts" Version="4.3.0" />
Expand All @@ -31,6 +31,7 @@

<ItemGroup>
<ProjectReference Include="..\nunit.analyzers\nunit.analyzers.csproj" OutputItemType="Analyzer" />
<ProjectReference Include="..\nunit.analyzers.codefixes\nunit.analyzers.codefixes.csproj" OutputItemType="Analyzer" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ arrayType.ElementType is ITypeParameterSymbol typeParameter &&
/// <remarks>
/// We only try to detect simple cases where the operands being tested for <see langword="null"/> is one of the operands being returned:
/// <code>variable is not null ? variable : otherExpression</code>
/// </para>
/// <para />
/// We recognize the 'is' pattern operations and normal equality.
/// </remarks>
/// <param name="conditionalExpression">Conditional expression to investigate.</param>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
Expand Down
2 changes: 2 additions & 0 deletions src/nunit.analyzers/Extensions/ITypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ internal static bool IsAwaitable(this ITypeSymbol @this,
/// <summary>
/// Return value indicates whether type implements IEnumerable interface.
/// </summary>
/// <param name="this">The <see cref="ITypeSymbol"/> to check.</param>
/// <param name="elementType">Contains IEnumerable generic argument, or null, if type implements
/// only non-generic IEnumerable interface, or no IEnumerable interface at all.</param>
internal static bool IsIEnumerable(this ITypeSymbol @this, out ITypeSymbol? elementType)
Expand Down Expand Up @@ -219,6 +220,7 @@ internal static bool IsIEnumerable(this ITypeSymbol @this, out ITypeSymbol? elem
/// <summary>
/// Return value indicates whether type implements I(Async)Enumerable{T} interface.
/// </summary>
/// <param name="this">The <see cref="ITypeSymbol"/> to check.</param>
/// <param name="elementType">Contains I(Async)Enumerable generic argument, or null, if type implements
/// only non-generic IEnumerable interface, or no I(Async)Enumerable interface at all.</param>
internal static bool IsIEnumerableOrIAsyncEnumerable(this ITypeSymbol @this, out ITypeSymbol? elementType)
Expand Down
2 changes: 1 addition & 1 deletion src/nunit.analyzers/Helpers/NUnitEqualityComparerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace NUnit.Analyzers.Helpers
internal static class NUnitEqualityComparerHelper
{
/// <summary>
/// Returns true if it is possible that <see cref="NUnit.Framework.Constraints.NUnitEqualityComparer.AreEqual"/>
/// Returns true if it is possible that "NUnit.Framework.Constraints.NUnitEqualityComparer.AreEqual"
/// returns true for given argument types.
/// False otherwise.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ protected override void AnalyzeAssertInvocation(OperationAnalysisContext context
continue;
}

var propertyMembers = actualType.GetAllMembers().Where(m => m.Kind == SymbolKind.Property);
var propertyMembers = actualType.GetAllMembers()
.Where(m => m.Kind == SymbolKind.Property)
.ToArray();
if (!propertyMembers.Any(m => m.Name == propertyName))
{
var properties = propertyMembers.Select(p => p.Name).Distinct().ToImmutableDictionary(p => p, p => (string?)p);
Expand Down
Loading
Loading