From e4bfbfd34e02bb496dc38cdc11630d0b093bed99 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:46:05 +0000 Subject: [PATCH 1/5] Initial plan From 3fe9d7b630d563c0af0cd0d79770da050bc9b34a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:02:28 +0000 Subject: [PATCH 2/5] Fix CA1869 to not report warnings in top-level statements Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- ...idSingleUseOfLocalJsonSerializerOptions.cs | 6 ++ ...gleUseOfLocalJsonSerializerOptionsTests.cs | 76 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs index 1744f9226673..b34dfdbc7afb 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs @@ -60,6 +60,12 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) INamedTypeSymbol? typeSymbol = operation.Constructor?.ContainingType; if (SymbolEqualityComparer.Default.Equals(typeSymbol, jsonSerializerOptionsSymbol)) { + // Don't report diagnostic for top-level statements as they only execute once + if (context.ContainingSymbol is IMethodSymbol method && method.IsTopLevelStatementsEntryPointMethod()) + { + return; + } + if (IsCtorUsedAsArgumentForJsonSerializer(operation, jsonSerializerSymbol) || IsLocalUsedAsArgumentForJsonSerializerOnly(operation, jsonSerializerSymbol, jsonSerializerOptionsSymbol)) { diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptionsTests.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptionsTests.cs index fad3c65d7cb3..3a7a7a7d0a66 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptionsTests.cs +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/tests/Microsoft.CodeAnalysis.NetAnalyzers.UnitTests/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptionsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Xunit; using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< @@ -820,6 +821,81 @@ Shared Function Serialize(Of T)(values As T()) As String End Function End Class """); + + [Fact] + public Task CS_TopLevelStatements_UseNewOptionsAsArgument_NoWarn() + { + var test = new VerifyCS.Test + { + TestState = + { + OutputKind = OutputKind.ConsoleApplication, + Sources = + { + """ + using System.Text.Json; + + string json = JsonSerializer.Serialize(new[] { 1, 2, 3 }, new JsonSerializerOptions { AllowTrailingCommas = true }); + """ + } + }, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9 + }; + return test.RunAsync(); + } + + [Fact] + public Task CS_TopLevelStatements_UseNewLocalOptionsAsArgument_NoWarn() + { + var test = new VerifyCS.Test + { + TestState = + { + OutputKind = OutputKind.ConsoleApplication, + Sources = + { + """ + using System.Text.Json; + + JsonSerializerOptions options = new() + { + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip + }; + + var output = JsonSerializer.Deserialize("[1,2,3]", options); + """ + } + }, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9 + }; + return test.RunAsync(); + } + + [Fact] + public Task CS_TopLevelStatements_UseNewLocalOptionsAsArgument_Assignment_NoWarn() + { + var test = new VerifyCS.Test + { + TestState = + { + OutputKind = OutputKind.ConsoleApplication, + Sources = + { + """ + using System.Text.Json; + + JsonSerializerOptions options; + options = new JsonSerializerOptions(); + + var output = JsonSerializer.Deserialize("[1,2,3]", options); + """ + } + }, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9 + }; + return test.RunAsync(); + } #endregion } } From 6b5dd5ae672bdd5bb271bd8fd208b0910f160979 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:07:57 +0000 Subject: [PATCH 3/5] Format AvoidSingleUseOfLocalJsonSerializerOptions.cs --- .../AvoidSingleUseOfLocalJsonSerializerOptions.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs index b34dfdbc7afb..ce6e323a53f1 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Analyzer.Utilities; using Analyzer.Utilities.Extensions; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -using System.Diagnostics.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.Diagnostics; namespace Microsoft.NetCore.Analyzers.Performance { From 4503744d891dc4c8a7d46e98e2889ebb85216d0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:08:41 +0000 Subject: [PATCH 4/5] Add formatting commit to .git-blame-ignore-revs Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .git-blame-ignore-revs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000000..0e6249e69b54 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,8 @@ +# This file contains commits that should be ignored by git blame +# Format: one commit SHA per line with optional comment +# +# To use this file, run: +# git config blame.ignoreRevsFile .git-blame-ignore-revs + +# Format AvoidSingleUseOfLocalJsonSerializerOptions.cs (imports ordering) +39fa404 From e74f06bbc63cf1e0becadbc2e334ee84b4ce09fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:54:11 +0000 Subject: [PATCH 5/5] Address PR feedback: update comment and remove unnecessary files Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .git-blame-ignore-revs | 8 -------- .../AvoidSingleUseOfLocalJsonSerializerOptions.cs | 2 +- .../src/RulesMissingDocumentation.md | 4 ++++ 3 files changed, 5 insertions(+), 9 deletions(-) delete mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 0e6249e69b54..000000000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,8 +0,0 @@ -# This file contains commits that should be ignored by git blame -# Format: one commit SHA per line with optional comment -# -# To use this file, run: -# git config blame.ignoreRevsFile .git-blame-ignore-revs - -# Format AvoidSingleUseOfLocalJsonSerializerOptions.cs (imports ordering) -39fa404 diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs index ce6e323a53f1..2bb19c228248 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers/Microsoft.NetCore.Analyzers/Performance/AvoidSingleUseOfLocalJsonSerializerOptions.cs @@ -60,7 +60,7 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) INamedTypeSymbol? typeSymbol = operation.Constructor?.ContainingType; if (SymbolEqualityComparer.Default.Equals(typeSymbol, jsonSerializerOptionsSymbol)) { - // Don't report diagnostic for top-level statements as they only execute once + // Don't report diagnostic for top-level statements as caching there is less impactful if (context.ContainingSymbol is IMethodSymbol method && method.IsTopLevelStatementsEntryPointMethod()) { return; diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md index 75e0f77588e2..c5820fde91ae 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md @@ -2,3 +2,7 @@ Rule ID | Missing Help Link | Title | --------|-------------------|-------| +CA1873 | | Avoid potentially expensive logging | +CA1874 | | Use 'Regex.IsMatch' | +CA1875 | | Use 'Regex.Count' | +CA2023 | | Invalid braces in message template |