diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs index 1141b27195ee1..ef895aa59d708 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs @@ -120,7 +120,12 @@ bool IsConstructibleCollectionType(ITypeSymbol type) return true; // At this point, all that is left are collection-initializer types. These need to derive from - // System.Collections.IEnumerable, and have an accessible no-arg constructor. + // System.Collections.IEnumerable, and have an invokable no-arg constructor. + + // Abstract type don't have invokable constructors at all. + if (namedType.IsAbstract) + return false; + if (namedType.AllInterfaces.Contains(compilation.IEnumerableType()!)) { // If they have an accessible `public C(int capacity)` constructor, the lang prefers calling that. diff --git a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForEmptyTests.cs b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForEmptyTests.cs index a93e3f5964913..a9fa58cdfcca3 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForEmptyTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForEmptyTests.cs @@ -1028,4 +1028,99 @@ void M() ReferenceAssemblies = ReferenceAssemblies.Net.Net80, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69507")] + public async Task NotForAbstractClassWithoutCollectionBuilderAttribute() + { + var collectionDefinition = """ + + abstract class V : IEnumerable + { + public static readonly V Empty = null; + + public V() { } + + public IEnumerator GetEnumerator() => default; + IEnumerator IEnumerable.GetEnumerator() => default; + + public void Add(T x) { } + } + """; + + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections; + using System.Collections.Generic; + + class C + { + void M() + { + V v = V.Empty; + } + } + """ + collectionDefinition, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69507")] + public async Task ForAbstractClassWithCollectionBuilderAttribute() + { + var collectionDefinition = """ + + [System.Runtime.CompilerServices.CollectionBuilder(typeof(V), "Create")] + abstract class V : IEnumerable + { + public static readonly V Empty = null; + + public V() { } + + public IEnumerator GetEnumerator() => default; + IEnumerator IEnumerable.GetEnumerator() => default; + + public void Add(T x) { } + } + + static class V + { + public static V Create(ReadOnlySpan values) => default; + } + """; + + await new VerifyCS.Test + { + TestCode = """ + using System; + using System.Collections; + using System.Collections.Generic; + + class C + { + void M() + { + V v = V.[|Empty|]; + } + } + """ + collectionDefinition, + FixedCode = """ + using System; + using System.Collections; + using System.Collections.Generic; + + class C + { + void M() + { + V v = []; + } + } + """ + collectionDefinition, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } }