From 443320d148d478751fbe78519cf213e8d12d111e Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Tue, 21 Nov 2023 21:58:40 +0100 Subject: [PATCH] Fix RCS1257 (#1264) --- ChangeLog.md | 3 +- .../CastExpressionCodeFixProvider.cs | 5 +-- .../UseEnumFieldExplicitlyAnalyzer.cs | 6 ++-- src/Core/ConvertHelpers.cs | 14 ++++++++ .../RCS1257UseEnumFieldExplicitlyTests.cs | 32 +++++++++++++++++++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 889b6df971..18658e9547 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [RCS1228](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1228) ([PR](https://github.com/dotnet/roslynator/pull/1249)) - Fix [RCS1213](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1213) ([PR](https://github.com/dotnet/roslynator/pull/1254)) - Fix [RCS1055](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1055) ([PR](https://github.com/dotnet/roslynator/pull/1253)) -- Fix [RCS1196](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1196/) ([PR](https://github.com/dotnet/roslynator/pull/1235)) +- Fix [RCS1196](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1196) ([PR](https://github.com/dotnet/roslynator/pull/1235)) +- Fix [RCS1257](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1257) ([PR](https://github.com/dotnet/roslynator/pull/1264)) ## [4.6.2] - 2023-11-10 diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/CastExpressionCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/CastExpressionCodeFixProvider.cs index 1c1bd8025d..d1fb6b4cc0 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/CastExpressionCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/CastExpressionCodeFixProvider.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; @@ -56,7 +57,7 @@ private static async Task UseEnumFieldExplicitlyAsync( if (enumSymbol.HasAttribute(MetadataNames.System_FlagsAttribute)) { - ulong value = SymbolUtility.GetEnumValueAsUInt64(constantValueOpt.Value, enumSymbol); + ulong value = Convert.ToUInt64(constantValueOpt.Value); List flags = FlagsUtility.Instance.GetFlags(value).ToList(); @@ -86,7 +87,7 @@ private static async Task UseEnumFieldExplicitlyAsync( .First(fieldSymbol => { return fieldSymbol.HasConstantValue - && constantValueOpt.Value.Equals(fieldSymbol.ConstantValue); + && Convert.ToUInt64(constantValueOpt.Value) == Convert.ToUInt64(fieldSymbol.ConstantValue); }); ExpressionSyntax newExpression = CreateEnumFieldExpression(symbol).WithTriviaFrom(castExpression); diff --git a/src/Analyzers/CSharp/Analysis/UseEnumFieldExplicitlyAnalyzer.cs b/src/Analyzers/CSharp/Analysis/UseEnumFieldExplicitlyAnalyzer.cs index 7e79e2f0cf..59abf6c73a 100644 --- a/src/Analyzers/CSharp/Analysis/UseEnumFieldExplicitlyAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/UseEnumFieldExplicitlyAnalyzer.cs @@ -64,13 +64,15 @@ private static void AnalyzeCastExpression(SyntaxNodeAnalysisContext context) if (enumSymbol?.EnumUnderlyingType is null) return; - ulong value = SymbolUtility.GetEnumValueAsUInt64(constantValueOpt.Value, enumSymbol); + if (!ConvertHelpers.TryConvertToUInt64(constantValueOpt.Value, out ulong value)) + return; foreach (ISymbol member in enumSymbol.GetMembers()) { if (member is IFieldSymbol fieldSymbol && fieldSymbol.HasConstantValue - && value == SymbolUtility.GetEnumValueAsUInt64(fieldSymbol.ConstantValue, enumSymbol)) + && ConvertHelpers.TryConvertToUInt64(fieldSymbol.ConstantValue, out ulong fieldValue) + && value == fieldValue) { context.ReportDiagnostic(DiagnosticRules.UseEnumFieldExplicitly, castExpression); return; diff --git a/src/Core/ConvertHelpers.cs b/src/Core/ConvertHelpers.cs index b8d6c014e8..2b9ae354f8 100644 --- a/src/Core/ConvertHelpers.cs +++ b/src/Core/ConvertHelpers.cs @@ -99,4 +99,18 @@ public static ulong ConvertToUInt64(object value, SpecialType numericType) throw new ArgumentException("", nameof(numericType)); } } + + public static bool TryConvertToUInt64(object value, out ulong result) + { + try + { + result = Convert.ToUInt64(value); + return true; + } + catch (Exception ex) when (ex is InvalidCastException || ex is OverflowException) + { + result = 0; + return false; + } + } } diff --git a/src/Tests/Analyzers.Tests/RCS1257UseEnumFieldExplicitlyTests.cs b/src/Tests/Analyzers.Tests/RCS1257UseEnumFieldExplicitlyTests.cs index 2cc4c11345..511104b21c 100644 --- a/src/Tests/Analyzers.Tests/RCS1257UseEnumFieldExplicitlyTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1257UseEnumFieldExplicitlyTests.cs @@ -64,6 +64,38 @@ void M() "); } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseEnumFieldExplicitly)] + public async Task Test_Flags_SByte() + { + await VerifyDiagnosticAndFixAsync(@" +class C +{ + void M() + { + var enumValue = [|(TestEnum)2|]; + } +} + +enum TestEnum : sbyte +{ + Foo, Bar, Baz +} +", @" +class C +{ + void M() + { + var enumValue = TestEnum.Baz; + } +} + +enum TestEnum : sbyte +{ + Foo, Bar, Baz +} +"); + } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseEnumFieldExplicitly)] public async Task TestNoDiagnostic_UndefinedValue() {