roslyn icon indicating copy to clipboard operation
roslyn copied to clipboard

[Visual Studio] [C# 14] Private extension methods incorrectly marked as unused members

Open vsfeedback opened this issue 1 month ago • 2 comments

This issue has been moved from a ticket on Developer Community.


[severity:It bothers me. A fix would be nice] When using the new C# 14 extension method syntax, Visual Studio 18.0.2 marks private extension methods as "unused members" but only if it is not called using the extension method signature. Surely this is the side-effect of some compiler lowering to old-style extension syntax, but the IDE suggestion is just wrong and would lead to a compiler error.

Example:

public static class NewStyleExtensions
{
    extension(string input)
    {
        public T[] SplitToArray<T>(char separator) where T : IConvertible
            => [.. input.Split(separator).Select(ConvertTo<T>)];

        private T ConvertTo<T>() where T : IConvertible   // <--- This method gets wrongfully marked as "unused member"
            => (T)Convert.ChangeType(input, typeof(T));
    }
}

Note that changing the call from the public method affects this behavior:

// Alternative 1
// When called with the true extension method signature, the private method is now correctly marked as "used".
public T[] SplitToArray<T>(char separator) where T : IConvertible
    => [.. input.Split(separator).Select(x => x.ConvertTo<T>())];

// Alternative 2
// When called with the target as an input parameter, the private method is incorrectly marked as "unused" and a refactor is suggested to remove the lambda expression (to original example above).
public T[] SplitToArray<T>(char separator) where T : IConvertible
    => [.. input.Split(separator).Select(x => ConvertTo<T>(x))]; 

Original Comments

Benjamin Copass on 12/11/2025, 01:27 AM:

Another example / use case:

internal static class PrivateExtensionPropertyTest
{
    extension(object o)
    {
        private bool Foo => o is null; // faded out in Visual Studio (VS thinks it's an unused member)
    }

public static void Test() { object o = new object(); bool b = o.Foo; // Foo is actually used } }

Feedback Bot on 12/11/2025, 06:50 AM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.

vsfeedback avatar Dec 11 '25 14:12 vsfeedback

Image

deepakrathore33 avatar Dec 11 '25 15:12 deepakrathore33

Related to https://github.com/dotnet/roslyn/issues/80645

deepakrathore33 avatar Dec 11 '25 15:12 deepakrathore33

Moved to Area-IDE as this seems driven by IDE0051 Also relates to https://github.com/dotnet/roslyn/issues/81213

I'm not sure if this is handled by the same IDE logic, but extension members and their implementation methods are also not tracked together in FAR and other refactorings: https://github.com/dotnet/roslyn/issues/81507

jcouv avatar Dec 12 '25 07:12 jcouv

Closing as duplicate of https://github.com/dotnet/roslyn/issues/80645 I'm working on a fix for 18.3

jcouv avatar Dec 17 '25 04:12 jcouv