Skip to content

Commit

Permalink
Merge pull request #831 from nunit/issue/677_NET8.0SDK
Browse files Browse the repository at this point in the history
Split off CodeFixes from analyzer
  • Loading branch information
mikkelbu authored Jan 25, 2025
2 parents a443ff6 + 0eddfe6 commit 83803de
Show file tree
Hide file tree
Showing 71 changed files with 87 additions and 188 deletions.
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
File renamed without changes.
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,10 @@ 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="tools\*.ps1" target="tools\" />
<file src="..\..\license.txt" target="" />
<file src="..\..\nunit_256.png" target="images" />
<file src="..\..\README.md" target="docs" />
<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="..\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

0 comments on commit 83803de

Please sign in to comment.