From 23a0c6976ea028d14b93808e2821efb01bea174a Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Sun, 26 Nov 2023 00:42:51 +0100 Subject: [PATCH 1/5] Fix analyzer RCS1158 --- ...nericTypeShouldUseTypeParameterAnalyzer.cs | 57 ++++++++++++++++++- ...nGenericTypeShouldUseTypeParameterTests.cs | 44 ++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs diff --git a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs index 0d18ee8a87..3dce109c27 100644 --- a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs @@ -1,9 +1,12 @@ // 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.Immutable; using System.Diagnostics; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace Roslynator.CSharp.Analysis; @@ -84,8 +87,14 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (typeParameters.IsDefault) typeParameters = namedType.TypeParameters; - if (!ContainsAnyTypeParameter(typeParameters, fieldSymbol.Type)) + if (!ContainsAnyTypeParameter(typeParameters, fieldSymbol.Type) + && !IsTypeParameterReferenced( + context, + typeParameters, + (fieldSymbol.GetSyntax(context.CancellationToken) as VariableDeclaratorSyntax)?.Initializer?.Value)) + { ReportDiagnostic(context, fieldSymbol); + } break; } @@ -116,8 +125,14 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (typeParameters.IsDefault) typeParameters = namedType.TypeParameters; - if (!ContainsAnyTypeParameter(typeParameters, propertySymbol.Type)) + if (!ContainsAnyTypeParameter(typeParameters, propertySymbol.Type) + && !IsTypeParameterReferenced( + context, + typeParameters, + (propertySymbol.GetSyntax(context.CancellationToken) as PropertyDeclarationSyntax)?.Initializer?.Value)) + { ReportDiagnostic(context, propertySymbol); + } } break; @@ -126,6 +141,44 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) } } + private static bool IsTypeParameterReferenced(SymbolAnalysisContext context, ImmutableArray typeParameters, ExpressionSyntax value) + { + if (value is null) + return false; + + if (value.IsKind(SyntaxKind.SimpleMemberAccessExpression)) + { + var memberAccess = (MemberAccessExpressionSyntax)value; + + if (memberAccess.Expression is IdentifierNameSyntax identifierName) + { + if (IsTypeParameter(identifierName, typeParameters)) + return true; + } + else if (memberAccess.Expression is TypeOfExpressionSyntax typeOfExpression) + { + if (typeOfExpression.Type is IdentifierNameSyntax identifierName2 + && IsTypeParameter(identifierName2, typeParameters)) + { + return true; + } + } + } + + return false; + + static bool IsTypeParameter(IdentifierNameSyntax identifierName, ImmutableArray typeParameters) + { + foreach (ITypeParameterSymbol typeParameter in typeParameters) + { + if (typeParameter.Name == identifierName.Identifier.ValueText) + return true; + } + + return false; + } + } + private static bool ContainsAnyTypeParameter(ImmutableArray typeParameters, ImmutableArray parameters) { foreach (IParameterSymbol parameter in parameters) diff --git a/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs b/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs new file mode 100644 index 0000000000..8e22c35336 --- /dev/null +++ b/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs @@ -0,0 +1,44 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Roslynator.Testing; +using Roslynator.Testing.CSharp; +using Xunit; + +namespace Roslynator.CSharp.Analysis.Tests; + +public class RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests : AbstractCSharpDiagnosticVerifier +{ + public override DiagnosticDescriptor Descriptor { get; } = DiagnosticRules.StaticMemberInGenericTypeShouldUseTypeParameter; + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.StaticMemberInGenericTypeShouldUseTypeParameter)] + public async Task TestNoDiagnostic_Property() + { + await VerifyNoDiagnosticAsync(@" +public sealed class C where T : IFoo +{ + public static string Name { get; } = T.Name; +} + +public interface IFoo +{ + public static abstract string Name { get; } +}"); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.StaticMemberInGenericTypeShouldUseTypeParameter)] + public async Task TestNoDiagnostic_Field() + { + await VerifyNoDiagnosticAsync(@" +public sealed class C where T : IFoo +{ + public static string Name = typeof(T).Name; +} + +public interface IFoo +{ + public static abstract string Name { get; } +}"); + } +} From d0613402489a40030f4e68231828d8e5d7939f3c Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Sun, 26 Nov 2023 00:44:16 +0100 Subject: [PATCH 2/5] update --- ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.md b/ChangeLog.md index f9fb09ca3d..38a52973de 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix analyzer [RCS1163](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1163) ([PR](https://github.com/dotnet/roslynator/pull/1280)) - Fix analyzer [RCS1203](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1203) ([PR](https://github.com/dotnet/roslynator/pull/1282)) - Fix analyzer [RCS1046](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1046) ([PR](https://github.com/dotnet/roslynator/pull/1283)) +- Fix analyzer [RCS1158](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1158) ([PR](https://github.com/dotnet/roslynator/pull/1288)) ## [4.6.4] - 2023-11-24 From c8d941028b6c1ad2e02e2225acf82efd69b84247 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Sun, 26 Nov 2023 00:47:31 +0100 Subject: [PATCH 3/5] update --- ...taticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs index 3dce109c27..989caf084a 100644 --- a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs @@ -1,9 +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.Immutable; using System.Diagnostics; -using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -143,9 +141,6 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) private static bool IsTypeParameterReferenced(SymbolAnalysisContext context, ImmutableArray typeParameters, ExpressionSyntax value) { - if (value is null) - return false; - if (value.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccess = (MemberAccessExpressionSyntax)value; From cec4c0707a6e4e9386d97cee52a06bcf23bee5bc Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Sun, 26 Nov 2023 00:48:01 +0100 Subject: [PATCH 4/5] update --- ...StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs index 989caf084a..56654183c8 100644 --- a/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/StaticMemberInGenericTypeShouldUseTypeParameterAnalyzer.cs @@ -87,7 +87,6 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (!ContainsAnyTypeParameter(typeParameters, fieldSymbol.Type) && !IsTypeParameterReferenced( - context, typeParameters, (fieldSymbol.GetSyntax(context.CancellationToken) as VariableDeclaratorSyntax)?.Initializer?.Value)) { @@ -125,7 +124,6 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (!ContainsAnyTypeParameter(typeParameters, propertySymbol.Type) && !IsTypeParameterReferenced( - context, typeParameters, (propertySymbol.GetSyntax(context.CancellationToken) as PropertyDeclarationSyntax)?.Initializer?.Value)) { @@ -139,7 +137,7 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) } } - private static bool IsTypeParameterReferenced(SymbolAnalysisContext context, ImmutableArray typeParameters, ExpressionSyntax value) + private static bool IsTypeParameterReferenced(ImmutableArray typeParameters, ExpressionSyntax value) { if (value.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { From f65d37088be5981643a0a079437f1795fc44abae Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Sun, 26 Nov 2023 01:27:57 +0100 Subject: [PATCH 5/5] update --- ...taticMemberInGenericTypeShouldUseTypeParameterTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs b/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs index 8e22c35336..28eebc6825 100644 --- a/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests.cs @@ -16,14 +16,14 @@ public class RCS1158StaticMemberInGenericTypeShouldUseTypeParameterTests : Abstr public async Task TestNoDiagnostic_Property() { await VerifyNoDiagnosticAsync(@" -public sealed class C where T : IFoo +public sealed class C where T : IFoo { - public static string Name { get; } = T.Name; + public static T2 Name { get; } = T.Name; } -public interface IFoo +public interface IFoo { - public static abstract string Name { get; } + public static abstract T Name { get; } }"); }