diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArrays.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArrays.cs index 2772cf5ea8..7336f096ab 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArrays.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArrays.cs @@ -42,6 +42,7 @@ public override void Initialize(AnalysisContext context) var knownTypeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation); INamedTypeSymbol? readonlySpanType = knownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemReadOnlySpan1); INamedTypeSymbol? functionType = knownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemFunc2); + INamedTypeSymbol? attributeType = knownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemAttribute); // Analyzes an argument operation context.RegisterOperationAction(context => @@ -59,7 +60,10 @@ public override void Initialize(AnalysisContext context) // If no argument, return // If argument is passed as a params array but isn't itself an array, return - if (argumentOperation?.Parameter is null || (argumentOperation.Parameter.IsParams && arrayCreationOperation.IsImplicit)) + // If array is declared as an attribute argument, return + if (argumentOperation?.Parameter is null + || (argumentOperation.Parameter.IsParams && arrayCreationOperation.IsImplicit) + || (argumentOperation.Parent is IObjectCreationOperation objectCreation && objectCreation.Type.Inherits(attributeType))) { return; } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArraysTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArraysTests.cs index aa9e6f48a3..c826fad825 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArraysTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/AvoidConstArraysTests.cs @@ -957,5 +957,70 @@ void A(char separatorArray0) return VerifyCS.VerifyCodeFixAsync(source, fixedSource); } + + [Fact, WorkItem(7033, "https://github.com/dotnet/roslyn-analyzers/issues/7033")] + public Task ArrayAsAttributeParameter_NoDiagnostic() + { + const string source = """ + using System; + + class Sample + { + [MyAttribute(new[] {"a", "b", "c"})] + void M() + { + } + } + + class MyAttribute : Attribute + { + public MyAttribute(string[] array) {} + } + """; + + return VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact, WorkItem(7033, "https://github.com/dotnet/roslyn-analyzers/issues/7033")] + public Task ArrayAsNamedAttributeParameter_NoDiagnostic() + { + const string source = """ + using System; + + class Sample + { + [MyAttribute(Values = new[] {"a", "b", "c"})] + void M() + { + } + } + + class MyAttribute : Attribute + { + public string[] Values { get; set; } + } + """; + + return VerifyCS.VerifyAnalyzerAsync(source); + } + + [Fact, WorkItem(7033, "https://github.com/dotnet/roslyn-analyzers/issues/7033")] + public Task ArrayAsAttributeParameter_Xunit_NoDiagnostic() + { + const string source = """ + public class Test + { + [Xunit.Theory] + [Xunit.InlineData("a", new[] { "b" })] + public void Method(string a, string[] b) { } + } + """; + + return new VerifyCS.Test + { + TestCode = source, + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithXUnit + }.RunAsync(); + } } }