Skip to content

Commit ad54ee4

Browse files
Fix issue with nameof(MemberGroup) caused us to consider all members used (#76335)
2 parents b437126 + 32e6565 commit ad54ee4

File tree

2 files changed

+112
-22
lines changed

2 files changed

+112
-22
lines changed

src/Analyzers/CSharp/Tests/RemoveUnusedMembers/RemoveUnusedMembersTests.cs

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,15 +1295,16 @@ class MyClass<T>
12951295
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31581")]
12961296
public async Task MethodInNameOf()
12971297
{
1298-
var code = """
1299-
class MyClass
1300-
{
1301-
private void M() { }
1302-
private string _goo = nameof(M);
1303-
}
1304-
""";
1305-
1306-
await VerifyCS.VerifyCodeFixAsync(code, code);
1298+
await new VerifyCS.Test
1299+
{
1300+
TestCode = """
1301+
class MyClass
1302+
{
1303+
private void M() { }
1304+
public string _goo = nameof(M);
1305+
}
1306+
""",
1307+
}.RunAsync();
13071308
}
13081309

13091310
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33765")]
@@ -3368,4 +3369,85 @@ struct S
33683369
ReferenceAssemblies = ReferenceAssemblies.Net.Net90,
33693370
}.RunAsync();
33703371
}
3372+
3373+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54972")]
3374+
public async Task TestNameof1()
3375+
{
3376+
await new VerifyCS.Test
3377+
{
3378+
TestCode = """
3379+
using System;
3380+
3381+
class Program
3382+
{
3383+
private int [|unused|];
3384+
3385+
static void Main(string[] args)
3386+
{
3387+
Console.WriteLine(nameof(Main));
3388+
}
3389+
}
3390+
""",
3391+
FixedCode = """
3392+
using System;
3393+
3394+
class Program
3395+
{
3396+
static void Main(string[] args)
3397+
{
3398+
Console.WriteLine(nameof(Main));
3399+
}
3400+
}
3401+
""",
3402+
LanguageVersion = LanguageVersion.CSharp13,
3403+
ReferenceAssemblies = ReferenceAssemblies.Net.Net90,
3404+
}.RunAsync();
3405+
}
3406+
3407+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54972")]
3408+
public async Task TestNameof2()
3409+
{
3410+
await new VerifyCS.Test
3411+
{
3412+
TestCode = """
3413+
using System;
3414+
3415+
class Program
3416+
{
3417+
private int used;
3418+
3419+
static void Main(string[] args)
3420+
{
3421+
Console.WriteLine(nameof(used));
3422+
}
3423+
}
3424+
""",
3425+
LanguageVersion = LanguageVersion.CSharp13,
3426+
ReferenceAssemblies = ReferenceAssemblies.Net.Net90,
3427+
}.RunAsync();
3428+
}
3429+
3430+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54972")]
3431+
public async Task TestNameof3()
3432+
{
3433+
await new VerifyCS.Test
3434+
{
3435+
TestCode = """
3436+
using System;
3437+
3438+
class Program
3439+
{
3440+
private void M() { }
3441+
private void M(int i) { }
3442+
3443+
static void Main(string[] args)
3444+
{
3445+
Console.WriteLine(nameof(M));
3446+
}
3447+
}
3448+
""",
3449+
LanguageVersion = LanguageVersion.CSharp13,
3450+
ReferenceAssemblies = ReferenceAssemblies.Net.Net90,
3451+
}.RunAsync();
3452+
}
33713453
}

src/Analyzers/Core/Analyzers/RemoveUnusedMembers/AbstractRemoveUnusedMembersDiagnosticAnalyzer.cs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,26 @@ private void RegisterActions(CompilationStartAnalysisContext compilationStartCon
220220

221221
var hasUnsupportedOperation = false;
222222
symbolStartContext.RegisterOperationAction(
223-
_ => hasUnsupportedOperation = true,
224-
OperationKind.Invalid, OperationKind.None, OperationKind.DynamicIndexerAccess, OperationKind.DynamicInvocation, OperationKind.DynamicMemberReference, OperationKind.DynamicObjectCreation);
223+
context =>
224+
{
225+
var operation = context.Operation;
226+
227+
// 'nameof(argument)' currently returns a 'None' operation for its argument. We don't want this
228+
// to cause us to bail out of processing. Instead, we'll handle this case explicitly in AnalyzeNameOfOperation.
229+
if (operation is { Kind: OperationKind.None, Parent: INameOfOperation { Argument: var nameofArgument } } &&
230+
nameofArgument == operation)
231+
{
232+
return;
233+
}
234+
235+
hasUnsupportedOperation = true;
236+
},
237+
OperationKind.Invalid,
238+
OperationKind.None,
239+
OperationKind.DynamicIndexerAccess,
240+
OperationKind.DynamicInvocation,
241+
OperationKind.DynamicMemberReference,
242+
OperationKind.DynamicObjectCreation);
225243

226244
symbolStartContext.RegisterSymbolEndAction(symbolEndContext => OnSymbolEnd(symbolEndContext, hasUnsupportedOperation));
227245

@@ -429,17 +447,7 @@ private void AnalyzeNameOfOperation(OperationAnalysisContext operationContext)
429447
// a bound method group/property group.
430448
var symbolInfo = nameofArgument.SemanticModel!.GetSymbolInfo(nameofArgument.Syntax, operationContext.CancellationToken);
431449
foreach (var symbol in symbolInfo.GetAllSymbols())
432-
{
433-
switch (symbol.Kind)
434-
{
435-
// Handle potential references to methods/properties from missing IOperation
436-
// for method group/property group.
437-
case SymbolKind.Method:
438-
case SymbolKind.Property:
439-
OnSymbolUsage(symbol.OriginalDefinition, ValueUsageInfo.ReadWrite);
440-
break;
441-
}
442-
}
450+
OnSymbolUsage(symbol.OriginalDefinition, ValueUsageInfo.ReadWrite);
443451
}
444452

445453
private void AnalyzeObjectCreationOperation(OperationAnalysisContext operationContext)

0 commit comments

Comments
 (0)