From 377ee978e4615b9355c431bdb732ba7b81a06b06 Mon Sep 17 00:00:00 2001 From: jakubreznak Date: Fri, 27 Oct 2023 20:31:08 +0200 Subject: [PATCH 1/2] Fix RCS1234 --- ChangeLog.md | 4 ++ .../EnumMemberDeclarationCodeFixProvider.cs | 3 ++ .../CSharp/Analysis/EnumSymbolAnalyzer.cs | 6 +++ src/CSharp/CSharp/CSharpUtility.cs | 9 +++- .../RCS1234DuplicateEnumValueTests.cs | 44 +++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5121471662..26b8c0b87f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Fix [RCS1234](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1234) + ## [4.6.0] - 2023-10-18 ### Added diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs index 1c282cec2e..3030d0ad03 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs @@ -192,6 +192,9 @@ private static EnumMemberDeclarationSyntax FindMemberByValue( { foreach (EnumMemberDeclarationSyntax enumMember in enumDeclaration.Members) { + if (CSharpUtility.IsEnumMemberObsolete(enumMember)) + continue; + IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(enumMember, cancellationToken); if (!SymbolEqualityComparer.Default.Equals(fieldSymbolInfo.Symbol, fieldSymbol)) diff --git a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs index 27850aed95..8224f7472f 100644 --- a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs @@ -201,11 +201,17 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (enumMember1 is null) continue; + if (CSharpUtility.IsEnumMemberObsolete(enumMember1)) + continue; + var enumMember2 = (EnumMemberDeclarationSyntax)symbolInfo2.Symbol.GetSyntax(context.CancellationToken); if (enumMember2 is null) continue; + if (CSharpUtility.IsEnumMemberObsolete(enumMember2)) + continue; + ExpressionSyntax value1 = enumMember1.EqualsValue?.Value?.WalkDownParentheses(); ExpressionSyntax value2 = enumMember2.EqualsValue?.Value?.WalkDownParentheses(); diff --git a/src/CSharp/CSharp/CSharpUtility.cs b/src/CSharp/CSharp/CSharpUtility.cs index d0e5e36ba6..c7056fbc76 100644 --- a/src/CSharp/CSharp/CSharpUtility.cs +++ b/src/CSharp/CSharp/CSharpUtility.cs @@ -1,7 +1,7 @@ // 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.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -681,4 +681,11 @@ public static SeparatedSyntaxList GetTypeParameters(SyntaxN return null; } } + + public static bool IsEnumMemberObsolete(EnumMemberDeclarationSyntax enumMember) + { + return enumMember.AttributeLists + .SelectMany(attrList => attrList.Attributes) + .Any(attribute => attribute.Name.ToString() == "Obsolete"); + } } diff --git a/src/Tests/Analyzers.Tests/RCS1234DuplicateEnumValueTests.cs b/src/Tests/Analyzers.Tests/RCS1234DuplicateEnumValueTests.cs index 19322b887e..c15143a404 100644 --- a/src/Tests/Analyzers.Tests/RCS1234DuplicateEnumValueTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1234DuplicateEnumValueTests.cs @@ -114,6 +114,34 @@ enum E "); } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.DuplicateEnumValue)] + public async Task Test6() + { + await VerifyDiagnosticAndFixAsync(@" +using System; + +enum E +{ + [Obsolete] + A = 1, + + B = 1, + C = [|1|] +} +", @" +using System; + +enum E +{ + [Obsolete] + A = 1, + + B = 1, + C = B +} +"); + } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.DuplicateEnumValue)] public async Task TestNoDiagnostic() { @@ -124,4 +152,20 @@ enum E B = A }"); } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.DuplicateEnumValue)] + public async Task TestNoDiagnostic2() + { + await VerifyNoDiagnosticAsync(@" +using System; + +enum E +{ + [Obsolete] + A = 1, + + B = 1, +} +"); + } } From 783309d2e9e788440457517d2042ba2e7815bcff Mon Sep 17 00:00:00 2001 From: jakubreznak Date: Fri, 27 Oct 2023 23:49:18 +0200 Subject: [PATCH 2/2] CR changes --- .../CodeFixes/EnumMemberDeclarationCodeFixProvider.cs | 6 +++--- src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs | 10 ++++------ src/CSharp/CSharp/CSharpUtility.cs | 7 ++----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs index 3030d0ad03..c6795c2f89 100644 --- a/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs +++ b/src/Analyzers.CodeFixes/CSharp/CodeFixes/EnumMemberDeclarationCodeFixProvider.cs @@ -192,11 +192,11 @@ private static EnumMemberDeclarationSyntax FindMemberByValue( { foreach (EnumMemberDeclarationSyntax enumMember in enumDeclaration.Members) { - if (CSharpUtility.IsEnumMemberObsolete(enumMember)) - continue; - IFieldSymbol fieldSymbol = semanticModel.GetDeclaredSymbol(enumMember, cancellationToken); + if (CSharpUtility.IsSymbolObsolete(fieldSymbol)) + continue; + if (!SymbolEqualityComparer.Default.Equals(fieldSymbolInfo.Symbol, fieldSymbol)) { EnumFieldSymbolInfo fieldSymbolInfo2 = EnumFieldSymbolInfo.Create(fieldSymbol); diff --git a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs index 8224f7472f..5bad422e50 100644 --- a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs @@ -196,22 +196,20 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) continue; } + if (CSharpUtility.IsSymbolObsolete(symbolInfo1.Symbol) + || CSharpUtility.IsSymbolObsolete(symbolInfo2.Symbol)) + continue; + var enumMember1 = (EnumMemberDeclarationSyntax)symbolInfo1.Symbol.GetSyntax(context.CancellationToken); if (enumMember1 is null) continue; - if (CSharpUtility.IsEnumMemberObsolete(enumMember1)) - continue; - var enumMember2 = (EnumMemberDeclarationSyntax)symbolInfo2.Symbol.GetSyntax(context.CancellationToken); if (enumMember2 is null) continue; - if (CSharpUtility.IsEnumMemberObsolete(enumMember2)) - continue; - ExpressionSyntax value1 = enumMember1.EqualsValue?.Value?.WalkDownParentheses(); ExpressionSyntax value2 = enumMember2.EqualsValue?.Value?.WalkDownParentheses(); diff --git a/src/CSharp/CSharp/CSharpUtility.cs b/src/CSharp/CSharp/CSharpUtility.cs index c7056fbc76..62cdac0af9 100644 --- a/src/CSharp/CSharp/CSharpUtility.cs +++ b/src/CSharp/CSharp/CSharpUtility.cs @@ -1,7 +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.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -682,10 +681,8 @@ public static SeparatedSyntaxList GetTypeParameters(SyntaxN } } - public static bool IsEnumMemberObsolete(EnumMemberDeclarationSyntax enumMember) + public static bool IsSymbolObsolete(ISymbol symbol) { - return enumMember.AttributeLists - .SelectMany(attrList => attrList.Attributes) - .Any(attribute => attribute.Name.ToString() == "Obsolete"); + return symbol.HasAttribute(MetadataNames.System_ObsoleteAttribute); } }