From 886490ad336812269d700352f9127e198daf7c13 Mon Sep 17 00:00:00 2001 From: Tim Cassell Date: Sat, 19 Sep 2026 06:32:44 -0400 Subject: [PATCH] Drop analyzer versions that cannot be loaded. --- .../Runners/BuildRunner.cs | 2 +- build/roslynBands.props | 9 ++-- .../AnalyzerHelper.cs | 15 ++----- .../GeneralParameterAttributesAnalyzer.cs | 5 +-- .../BenchmarkDotNet.Analyzers.csproj | 11 ++--- .../Polyfills/RefLikeTypePolyfill.cs | 41 ------------------- .../Polyfills/SymbolEqualityComparer.cs | 19 --------- .../BenchmarkDotNet.Annotations.targets | 20 +++++++++ 8 files changed, 35 insertions(+), 87 deletions(-) delete mode 100644 src/BenchmarkDotNet.Analyzers/Polyfills/RefLikeTypePolyfill.cs delete mode 100644 src/BenchmarkDotNet.Analyzers/Polyfills/SymbolEqualityComparer.cs diff --git a/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs index df56308025..7acfc97788 100644 --- a/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs +++ b/build/BenchmarkDotNet.Build/Runners/BuildRunner.cs @@ -126,7 +126,7 @@ public void BuildAnalyzers() context.Information("BuildSystemProvider: " + context.BuildSystem().Provider); // Each band must restore as well as build: the PackageReference is chosen by MccVersion, so reusing the // default band's project.assets.json silently compiles every band against the default's Roslyn. - string[] mccVersions = ["2.8", "3.0", "3.8", "4.4", "4.8", "4.12"]; + string[] mccVersions = ["4.0", "4.4", "4.8", "4.12"]; foreach (string version in mccVersions) { context.DotNetBuild(context.AnalyzersProjectFile.FullPath, new DotNetBuildSettings diff --git a/build/roslynBands.props b/build/roslynBands.props index 07375d64ef..a207557fb2 100644 --- a/build/roslynBands.props +++ b/build/roslynBands.props @@ -10,11 +10,10 @@ bin\$(Configuration)\roslyn$(MccVersion)\cs false - - - $(DefineConstants);CODE_ANALYSIS_3_0 - - $(DefineConstants);CODE_ANALYSIS_3_8 + $(DefineConstants);CODE_ANALYSIS_4_4 diff --git a/src/BenchmarkDotNet.Analyzers/AnalyzerHelper.cs b/src/BenchmarkDotNet.Analyzers/AnalyzerHelper.cs index 3a5450691c..6db6b69a5b 100644 --- a/src/BenchmarkDotNet.Analyzers/AnalyzerHelper.cs +++ b/src/BenchmarkDotNet.Analyzers/AnalyzerHelper.cs @@ -148,23 +148,14 @@ public static bool MayBeRefLike(ITypeSymbol type) return true; } #endif - return IsRefLikeType(type); + return type.IsRefLikeType; } - // ref structs are C# 7.2, but no public symbol carries IsRefLikeType until Roslyn 3.0; the oldest band reads - // the internal property behind it instead. - private static bool IsRefLikeType(ITypeSymbol type) -#if CODE_ANALYSIS_3_0 - => type.IsRefLikeType; -#else - => RefLikeTypePolyfill.IsRefLikeType(type); -#endif - /// /// Names which of the two found, so a message reads the same from either source analyzer. /// public static string ByRefLikeClause(ITypeSymbol type) - => IsRefLikeType(type) ? "is a ref struct" : "admits a ref struct"; + => type.IsRefLikeType ? "is a ref struct" : "admits a ref struct"; /// /// Which of the two rules applies. A ref struct is one the compiler can see, so the source cannot work; a @@ -172,7 +163,7 @@ public static string ByRefLikeClause(ITypeSymbol type) /// perfectly well - so the two are separate ids, configurable apart. /// public static DiagnosticDescriptor ByRefLikeRule(ITypeSymbol type) - => IsRefLikeType(type) ? SourceElementMustNotBeByRefLikeRule : SourceElementMayBeByRefLikeRule; + => type.IsRefLikeType ? SourceElementMustNotBeByRefLikeRule : SourceElementMayBeByRefLikeRule; /// /// Whether is or derives from it. BenchmarkDotNet resolves diff --git a/src/BenchmarkDotNet.Analyzers/Attributes/GeneralParameterAttributesAnalyzer.cs b/src/BenchmarkDotNet.Analyzers/Attributes/GeneralParameterAttributesAnalyzer.cs index 5c67e8c25a..f661af121a 100644 --- a/src/BenchmarkDotNet.Analyzers/Attributes/GeneralParameterAttributesAnalyzer.cs +++ b/src/BenchmarkDotNet.Analyzers/Attributes/GeneralParameterAttributesAnalyzer.cs @@ -197,10 +197,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context) // `init` counts: the runnable assigns parameters through an object initializer. var propertyAccessors = propertyDeclarationSyntax.AccessorList?.Accessors; propertyIsMissingAssignableSetter = !HasAssignableAccessor(propertyAccessors, SyntaxKind.SetAccessorDeclaration) -#if CODE_ANALYSIS_3_8 - && !HasAssignableAccessor(propertyAccessors, SyntaxKind.InitAccessorDeclaration) -#endif - ; + && !HasAssignableAccessor(propertyAccessors, SyntaxKind.InitAccessorDeclaration); fieldOrPropertyIdentifierLocation = propertyDeclarationSyntax.Identifier.GetLocation(); declaredNames = ImmutableArray.Create((fieldOrPropertyIdentifier, fieldOrPropertyIdentifierLocation)); diff --git a/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj b/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj index 722341534f..ba0987eb7d 100644 --- a/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj +++ b/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj @@ -8,11 +8,12 @@ $(NoWarn);RS2007 - - $(NoWarn);RS2002 - - - + + $(NoWarn);RS1024 + + + diff --git a/src/BenchmarkDotNet.Analyzers/Polyfills/RefLikeTypePolyfill.cs b/src/BenchmarkDotNet.Analyzers/Polyfills/RefLikeTypePolyfill.cs deleted file mode 100644 index 21f1911e42..0000000000 --- a/src/BenchmarkDotNet.Analyzers/Polyfills/RefLikeTypePolyfill.cs +++ /dev/null @@ -1,41 +0,0 @@ -#if !CODE_ANALYSIS_3_0 -using System.Reflection; -using Microsoft.CodeAnalysis.CSharp; - -namespace Microsoft.CodeAnalysis; - -// ITypeSymbol.IsRefLikeType only appears in Roslyn 3.0 (dotnet/roslyn#30426), though the compiler has tracked -// ref-likeness since C# 7.2 - as the internal TypeSymbol.IsByRefLikeType this reads. Reflection rather than the -// metadata attribute because that route is deliberately closed: PENamedTypeSymbol.GetAttributes filters -// IsByRefLikeAttribute out exactly when the type is ref-like, so a referenced Span reports no such attribute. -// The property is declared on the base and overridden per symbol kind, so one lookup serves every kind. -// -// Both guards below answer false rather than throwing, because an exception escaping an analyzer is reported as -// AD0001 and disables it. The lookup is guarded because a failure in a static initializer poisons the type for -// every later call; the instance check is guarded because GetValue is the one call here that can throw, and does -// so only for an ITypeSymbol that is not a Roslyn C# symbol - which the language filter on every analyzer here -// makes unreachable, RS1009 forbids implementing, and a runtime mock could still produce. -internal static class RefLikeTypePolyfill -{ - private static readonly PropertyInfo? IsByRefLikeType = ResolveIsByRefLikeType(); - - internal static bool IsRefLikeType(ITypeSymbol type) - => IsByRefLikeType is { } property - && property.DeclaringType!.IsInstanceOfType(type) - && property.GetValue(type) is true; - - private static PropertyInfo? ResolveIsByRefLikeType() - { - try - { - return typeof(CSharpCompilation).Assembly - .GetType("Microsoft.CodeAnalysis.CSharp.Symbols.TypeSymbol") - ?.GetProperty("IsByRefLikeType", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - } - catch - { - return null; - } - } -} -#endif diff --git a/src/BenchmarkDotNet.Analyzers/Polyfills/SymbolEqualityComparer.cs b/src/BenchmarkDotNet.Analyzers/Polyfills/SymbolEqualityComparer.cs deleted file mode 100644 index ac350dc5fb..0000000000 --- a/src/BenchmarkDotNet.Analyzers/Polyfills/SymbolEqualityComparer.cs +++ /dev/null @@ -1,19 +0,0 @@ -#if !CODE_ANALYSIS_3_8 -using System.Collections.Generic; - -namespace Microsoft.CodeAnalysis; - -// SymbolEqualityComparer appears in Roslyn 3.3, so the 2.8 and 3.0 bands compare symbols through ISymbol.Equals, -// as callers did before it existed. Declared in Roslyn's own namespace, so the call sites read the same on -// every band. -internal sealed class SymbolEqualityComparer : IEqualityComparer -{ - internal static readonly SymbolEqualityComparer Default = new(); - - private SymbolEqualityComparer() { } - - public bool Equals(ISymbol? x, ISymbol? y) => x is null ? y is null : x.Equals(y); - - public int GetHashCode(ISymbol obj) => obj.GetHashCode(); -} -#endif diff --git a/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets b/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets index c6dda74663..16e87db341 100644 --- a/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets +++ b/src/BenchmarkDotNet.Annotations/buildTransitive/netstandard2.0/BenchmarkDotNet.Annotations.targets @@ -8,4 +8,24 @@ + + + + <_BenchmarkDotNetAnalyzer Include="@(Analyzer)" Condition="'%(Analyzer.NuGetPackageId)' == 'BenchmarkDotNet.Annotations'" /> + + + + + + + + +