From 883250d14fb55953335ac974dfd1bd8e51666431 Mon Sep 17 00:00:00 2001 From: Collin Alpert Date: Sat, 9 Dec 2023 15:23:15 +0100 Subject: [PATCH 1/2] Suppress CA1862 for string.Contains on netfx --- ...aseInsensitiveStringComparison.Analyzer.cs | 14 +++-- ...nsensitiveStringComparison.CSharp.Tests.cs | 61 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.Analyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.Analyzer.cs index 9b1493d3fe..87cc05d5cc 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.Analyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.Analyzer.cs @@ -34,7 +34,6 @@ public sealed class RecommendCaseInsensitiveStringComparisonAnalyzer : Diagnosti internal const string StringIndexOfMethodName = "IndexOf"; internal const string StringStartsWithMethodName = "StartsWith"; internal const string StringCompareToMethodName = "CompareTo"; - internal const string StringComparerCompareMethodName = "Compare"; internal const string StringEqualsMethodName = "Equals"; internal const string StringParameterName = "value"; internal const string StringComparisonParameterName = "comparisonType"; @@ -211,12 +210,19 @@ private void AnalyzeCompilationStart(CompilationStartAnalysisContext context) return; } + ParameterInfo[] stringStringComparisonParameters = { + ParameterInfo.GetParameterInfo(stringType), + ParameterInfo.GetParameterInfo(stringComparisonType) + }; + IMethodSymbol? containsStringWithStringComparisonMethod + = stringType.GetMembers(StringContainsMethodName).OfType().GetFirstOrDefaultMemberWithParameterInfos(stringStringComparisonParameters); + // a.ToLower().Method(b.ToLower()) context.RegisterOperationAction(context => { IInvocationOperation invocation = (IInvocationOperation)context.Operation; AnalyzeInvocation(context, invocation, stringType, - containsStringMethod, startsWithStringMethod, compareToStringMethod, + containsStringMethod, containsStringWithStringComparisonMethod, startsWithStringMethod, compareToStringMethod, indexOfStringMethod, indexOfStringInt32Method, indexOfStringInt32Int32Method); }, OperationKind.Invocation); @@ -230,13 +236,13 @@ private void AnalyzeCompilationStart(CompilationStartAnalysisContext context) } private static void AnalyzeInvocation(OperationAnalysisContext context, IInvocationOperation invocation, INamedTypeSymbol stringType, - IMethodSymbol containsStringMethod, IMethodSymbol startsWithStringMethod, IMethodSymbol compareToStringMethod, + IMethodSymbol containsStringMethod, IMethodSymbol? containsStringWithStringComparisonMethod, IMethodSymbol startsWithStringMethod, IMethodSymbol compareToStringMethod, IMethodSymbol indexOfStringMethod, IMethodSymbol indexOfStringInt32Method, IMethodSymbol indexOfStringInt32Int32Method) { IMethodSymbol diagnosableMethod = invocation.TargetMethod; DiagnosticDescriptor? chosenRule; - if (diagnosableMethod.Equals(containsStringMethod) || + if (diagnosableMethod.Equals(containsStringMethod) && containsStringWithStringComparisonMethod is not null || diagnosableMethod.Equals(startsWithStringMethod) || diagnosableMethod.Equals(indexOfStringMethod) || diagnosableMethod.Equals(indexOfStringInt32Method) || diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.CSharp.Tests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.CSharp.Tests.cs index bea4a72791..6b835da3a7 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.CSharp.Tests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Performance/RecommendCaseInsensitiveStringComparison.CSharp.Tests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Testing; +using Test.Utilities; using Xunit; using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< Microsoft.NetCore.Analyzers.Performance.RecommendCaseInsensitiveStringComparisonAnalyzer, @@ -370,6 +371,66 @@ bool M() await VerifyFixCSharpAsync(originalCode, originalCode); } + [Fact, WorkItem(7053, "https://github.com/dotnet/roslyn-analyzers/issues/7053")] + public Task Net48_Contains_NoDiagnostic() + { + const string code = """ + using System; + + class C + { + void M(string s) + { + s.ToUpperInvariant().Contains("ABC"); + } + } + """; + + return new VerifyCS.Test + { + TestCode = code, + ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net48.Default, + MarkupOptions = MarkupOptions.UseFirstDescriptor + }.RunAsync(); + } + + [Theory, WorkItem(7053, "https://github.com/dotnet/roslyn-analyzers/issues/7053")] + [InlineData("StartsWith")] + [InlineData("IndexOf")] + public Task Net48_Diagnostic(string method) + { + var code = $$""" + using System; + + class C + { + void M(string s) + { + [|s.ToUpperInvariant().{{method}}("ABC")|]; + } + } + """; + var fixedCode = $$""" + using System; + + class C + { + void M(string s) + { + s.{{method}}("ABC", StringComparison.InvariantCultureIgnoreCase); + } + } + """; + + return new VerifyCS.Test + { + TestCode = code, + FixedCode = fixedCode, + ReferenceAssemblies = ReferenceAssemblies.NetFramework.Net48.Default, + MarkupOptions = MarkupOptions.UseFirstDescriptor + }.RunAsync(); + } + private async Task VerifyNoDiagnosticCSharpAsync(string originalSource) { VerifyCS.Test test = new() From 1e572fc18810189899e740011dafc58721b1b99b Mon Sep 17 00:00:00 2001 From: Collin Alpert Date: Sat, 9 Dec 2023 15:42:18 +0100 Subject: [PATCH 2/2] Update RulesMissingDocumentation.md --- src/NetAnalyzers/RulesMissingDocumentation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NetAnalyzers/RulesMissingDocumentation.md b/src/NetAnalyzers/RulesMissingDocumentation.md index 0c3d9d554b..fe3e164155 100644 --- a/src/NetAnalyzers/RulesMissingDocumentation.md +++ b/src/NetAnalyzers/RulesMissingDocumentation.md @@ -2,5 +2,4 @@ Rule ID | Missing Help Link | Title | --------|-------------------|-------| -CA1515 | | Consider making public types internal | CA2262 | | Set 'MaxResponseHeadersLength' properly |