From 9f10355a3f079298421cb8d39e0d681c0ab2ca1f Mon Sep 17 00:00:00 2001 From: James May Date: Fri, 14 Feb 2025 11:43:12 +1100 Subject: [PATCH] fix false positive casting from value type constraint to Enum or ValueType #7031 --- ...stOrOfTypeWithIncompatibleTypesAnalyzer.cs | 3 +- ...fTypeWithIncompatibleTypesAnalyzerTests.cs | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs index bc3dda1329..0542458402 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs @@ -267,7 +267,8 @@ static bool IsUnconstrainedTypeParameter(ITypeParameterSymbol typeParameterSymbo if (castToTypeParam.HasValueTypeConstraint && castFrom.TypeKind == TypeKind.Class) { - return true; + return castFrom.SpecialType is not SpecialType.System_Enum + and not SpecialType.System_ValueType; } return false; diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs index 7e6523ce82..23337eb425 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs @@ -910,6 +910,35 @@ class GenericDerived : GenericBase await test.RunAsync(); } + [Fact, WorkItem(7031, "https://github.com/dotnet/roslyn-analyzers/issues/7031")] + public async Task GenericValueType() + { + // ensure runtime behavior is matches + _ = new Enum[] { StringComparison.OrdinalIgnoreCase }.Cast().ToArray(); + _ = new ValueType[] { int.MaxValue }.Cast().ToArray(); + + var test = new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + LanguageVersion = LanguageVersion.Latest, + + TestCode = @" +using System; +using System.Collections.Generic; +using System.Linq; + +public static class Program +{ + public static IEnumerable CastEnums(IEnumerable values) where T : struct, Enum + => values.Cast(); // CA2021 + + public static IEnumerable CastValueTypes(IEnumerable values) where T : struct + => values.Cast(); // CA2021 +}" + }; + await test.RunAsync(); + } + [Fact] public async Task NonGenericCasesVB() {