Skip to content

Commit

Permalink
Merge pull request #45090 from sharwell/unused-main
Browse files Browse the repository at this point in the history
Exclude entry points from unused members analysis
  • Loading branch information
sharwell authored Jun 12, 2020
2 parents f943a1a + 5cc698b commit 6db6c5e
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
Expand Down Expand Up @@ -356,6 +358,113 @@ class MyClass
await VerifyCS.VerifyCodeFixAsync(code, code);
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task EntryPointMethodNotFlagged_06()
{
var code = @"
return 0;
";

await new VerifyCS.Test
{
TestCode = code,
FixedCode = code,
ExpectedDiagnostics =
{
// error CS8805: Program using top-level statements must be an executable.
DiagnosticResult.CompilerError("CS8805"),
},
LanguageVersion = LanguageVersionExtensions.CSharp9,
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task EntryPointMethodNotFlagged_07()
{
var code = @"
return 0;
";

await new VerifyCS.Test
{
TestState =
{
Sources = { code, code },
},
FixedState =
{
Sources = { code, code },
},
ExpectedDiagnostics =
{
// error CS8805: Program using top-level statements must be an executable.
DiagnosticResult.CompilerError("CS8805"),
// /0/Test1.cs(2,1): error CS8802: Only one compilation unit can have top-level statements.
DiagnosticResult.CompilerError("CS8802").WithSpan("/0/Test1.cs", 2, 1, 2, 7),
},
LanguageVersion = LanguageVersionExtensions.CSharp9,
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task EntryPointMethodNotFlagged_08()
{
var code = @"
return 0;
";

await new VerifyCS.Test
{
TestCode = code,
FixedCode = code,
SolutionTransforms =
{
(solution, projectId) =>
{
var project = solution.GetRequiredProject(projectId);
var compilationOptions = project.CompilationOptions;
return solution.WithProjectCompilationOptions(projectId, compilationOptions.WithOutputKind(OutputKind.ConsoleApplication));
},
},
LanguageVersion = LanguageVersionExtensions.CSharp9,
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task EntryPointMethodNotFlagged_09()
{
var code = @"
return 0;
";

await new VerifyCS.Test
{
TestState =
{
Sources = { code, code },
},
FixedState =
{
Sources = { code, code },
},
ExpectedDiagnostics =
{
// /0/Test1.cs(2,1): error CS8802: Only one compilation unit can have top-level statements.
DiagnosticResult.CompilerError("CS8802").WithSpan("/0/Test1.cs", 2, 1, 2, 7),
},
SolutionTransforms =
{
(solution, projectId) =>
{
var project = solution.GetRequiredProject(projectId);
var compilationOptions = project.CompilationOptions;
return solution.WithProjectCompilationOptions(projectId, compilationOptions.WithOutputKind(OutputKind.ConsoleApplication));
},
},
LanguageVersion = LanguageVersionExtensions.CSharp9,
}.RunAsync();
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task FieldIsUnused_ReadOnly()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,16 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsuppo
ArrayBuilder<string> debuggerDisplayAttributeArguments = null;
try
{
var entryPoint = symbolEndContext.Compilation.GetEntryPoint(symbolEndContext.CancellationToken);

var namedType = (INamedTypeSymbol)symbolEndContext.Symbol;
foreach (var member in namedType.GetMembers())
{
if (SymbolEqualityComparer.Default.Equals(entryPoint, member))
{
continue;
}

// Check if the underlying member is neither read nor a readable reference to the member is taken.
// If so, we flag the member as either unused (never written) or unread (written but not read).
if (TryRemove(member, out var valueUsageInfo) &&
Expand Down Expand Up @@ -689,7 +696,7 @@ private bool IsCandidateSymbol(ISymbol memberSymbol)
}

private bool IsEntryPoint(IMethodSymbol methodSymbol)
=> methodSymbol.Name == WellKnownMemberNames.EntryPointMethodName &&
=> (methodSymbol.Name == WellKnownMemberNames.EntryPointMethodName || methodSymbol.Name == "$Main") &&
methodSymbol.IsStatic &&
(methodSymbol.ReturnsVoid ||
methodSymbol.ReturnType.SpecialType == SpecialType.System_Int32 ||
Expand Down

0 comments on commit 6db6c5e

Please sign in to comment.