Skip to content

Commit 3515b06

Browse files
Don't emit CA1861 for static ReadOnlyCollections (#6644)
* Don't warn for static ReadOnlyCollections. * Do not warn on static initializers --------- Co-authored-by: Buyaa Namnan <[email protected]>
1 parent 19e1393 commit 3515b06

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArrays.cs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ public override void Initialize(AnalysisContext context)
3939

4040
context.RegisterCompilationStartAction(context =>
4141
{
42-
INamedTypeSymbol? readonlySpanType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemReadOnlySpan1);
43-
INamedTypeSymbol? functionType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemFunc2);
42+
var knownTypeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation);
43+
INamedTypeSymbol? readonlySpanType = knownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemReadOnlySpan1);
44+
INamedTypeSymbol? functionType = knownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemFunc2);
4445

4546
// Analyzes an argument operation
4647
context.RegisterOperationAction(context =>
@@ -110,12 +111,7 @@ public override void Initialize(AnalysisContext context)
110111
string? paramName = null;
111112
if (argumentOperation is not null)
112113
{
113-
IFieldInitializerOperation? fieldInitializer = argumentOperation.GetAncestor<IFieldInitializerOperation>(
114-
OperationKind.FieldInitializer, f => f.InitializedFields.Any(x => x.IsReadOnly));
115-
IPropertyInitializerOperation? propertyInitializer = argumentOperation.GetAncestor<IPropertyInitializerOperation>(
116-
OperationKind.PropertyInitializer, p => p.InitializedProperties.Any(x => x.IsReadOnly));
117-
118-
if (fieldInitializer is not null || propertyInitializer is not null)
114+
if (IsInitializingStaticOrReadOnlyFieldOrProperty(argumentOperation))
119115
{
120116
return;
121117
}
@@ -149,5 +145,40 @@ public override void Initialize(AnalysisContext context)
149145
OperationKind.Invocation);
150146
});
151147
}
148+
149+
private static bool IsInitializingStaticOrReadOnlyFieldOrProperty(IOperation operation)
150+
{
151+
var ancestor = operation;
152+
do
153+
{
154+
ancestor = ancestor!.Parent;
155+
} while (ancestor != null && !(ancestor.Kind == OperationKind.FieldInitializer || ancestor.Kind == OperationKind.PropertyInitializer ||
156+
ancestor.Kind == OperationKind.CoalesceAssignment || ancestor.Kind == OperationKind.SimpleAssignment));
157+
158+
if (ancestor != null)
159+
{
160+
switch (ancestor)
161+
{
162+
case IFieldInitializerOperation fieldInitializer:
163+
return fieldInitializer.InitializedFields.Any(x => x.IsStatic || x.IsReadOnly);
164+
case IPropertyInitializerOperation propertyInitializer:
165+
return propertyInitializer.InitializedProperties.Any(x => x.IsStatic || x.IsReadOnly);
166+
case IAssignmentOperation assignmentOperation:
167+
if (assignmentOperation.Target is IFieldReferenceOperation fieldReference && fieldReference.Field.IsStatic)
168+
{
169+
return true;
170+
}
171+
172+
if (assignmentOperation.Target is IPropertyReferenceOperation propertyReference && propertyReference.Property.IsStatic)
173+
{
174+
return true;
175+
}
176+
177+
break;
178+
}
179+
}
180+
181+
return false;
182+
}
152183
}
153184
}

src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArraysTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
22

33
using System.Threading.Tasks;
4+
using Microsoft.CodeAnalysis.CSharp;
5+
using Test.Utilities;
46
using Xunit;
57
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
68
Microsoft.NetCore.Analyzers.Runtime.AvoidConstArraysAnalyzer,
@@ -766,6 +768,7 @@ await VerifyCS.VerifyAnalyzerAsync(@"
766768
767769
public class A
768770
{
771+
public readonly List<string> Field1 = GetValues(new string[] { ""close"" });
769772
public static readonly A Field;
770773
public static List<string> Property { get; } = GetValues(new string[] { ""close"" });
771774
public static string[] Property2 { get; } = new string[] { ""close"" };
@@ -779,5 +782,27 @@ public A(string[] arr) { }
779782
private static List<string> GetValues(string[] arr) => null;
780783
}");
781784
}
785+
786+
[Fact, WorkItem(6629, "https://github.com/dotnet/roslyn-analyzers/issues/6629")]
787+
public Task StaticReadonlyCollection_NoDiagnostic()
788+
{
789+
return new VerifyCS.Test
790+
{
791+
TestCode = @"
792+
#nullable enable
793+
using System.Collections.ObjectModel;
794+
795+
public class Test
796+
{
797+
private static ReadOnlyCollection<string>? s_errorPayloadNames;
798+
799+
private void M(string eventName, string msg)
800+
{
801+
s_errorPayloadNames ??= new ReadOnlyCollection<string>(new string[] { ""message"" });
802+
}
803+
}",
804+
LanguageVersion = LanguageVersion.CSharp8
805+
}.RunAsync();
806+
}
782807
}
783808
}

0 commit comments

Comments
 (0)