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..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 @@ -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 { @@ -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 caching there is less impactful + if (context.ContainingSymbol is IMethodSymbol method && method.IsTopLevelStatementsEntryPointMethod()) + { + return; + } + if (IsCtorUsedAsArgumentForJsonSerializer(operation, jsonSerializerSymbol) || IsLocalUsedAsArgumentForJsonSerializerOnly(operation, jsonSerializerSymbol, jsonSerializerOptionsSymbol)) { 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 | 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 } }