-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Remove Unused References dialog #49862
Merged
JoeRobich
merged 59 commits into
dotnet:features/UsedAssemblyReferences
from
JoeRobich:add-unusedreference-dialog
Feb 10, 2021
Merged
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
b90c777
Cleanup ReferenceCleanupService
JoeRobich 655c158
Add UnusedReferenceService to determine unused references
JoeRobich 93e4bb1
Add ProjectAssets model and reader
JoeRobich 98f10c7
Add string resources
JoeRobich 0806d81
Add unused reference columns definitions and table provider
JoeRobich 9e83175
Add remove unused references dialog
JoeRobich 0a4255e
Add Remove Unused References command.
JoeRobich d0130fb
Add command handler for the remove unused references command
JoeRobich 4cc3f12
Remove nullable pragmas
JoeRobich c818664
Handle case where compilation is null
JoeRobich 1068618
Add no unused references found popup
JoeRobich 6a1c0fb
Add comfirmation dialog when there are reference changes
JoeRobich cfac803
Add option to show Remove Unused Reference command
JoeRobich fe8b901
Add ellipses to command text
JoeRobich 491c32e
Remove TFM argument from UpdateReferencesAsync
JoeRobich ca8179a
Fix build error
JoeRobich 6e69823
Add tests for the UnusedReferencesService
JoeRobich 18f2655
Remove use of IEnumerable from UnusedReferencesService
JoeRobich 0d15843
Update ProjectAssetsReader comment with a tracking issue
JoeRobich eb4d85f
Add comment about ignoring empty files in ProjectAssetsReader
JoeRobich a3e0f83
Remove memoization of compilation assemblies from ReferenceInfo
JoeRobich 2f0c6f7
Remove empty line from UnusedReferencesService
JoeRobich 5e81897
Use GetRequiredProject extension method
JoeRobich 2e2efdf
Update method name for clarity
JoeRobich 76a4792
Move GetAllCompilationAssemblies out of ReferenceInfo
JoeRobich 287d54a
Use mutable usedAssemblyLookup in UnusedReferencesService
JoeRobich 7314957
Code cleanup
JoeRobich f816a38
Add clarifying comments
JoeRobich b501f74
Use TryGetValue instead of multiple dictionary accesses
JoeRobich a13c308
Extract out a CommandHelpers class of common code.
JoeRobich a0b7522
Fix accessibility of Actions ComboBox
JoeRobich cfd230b
Update string resources
JoeRobich 30eebaf
Update parameter name for clarity
JoeRobich ab85d79
Updated command placement and cleaned up Commands.vsct
JoeRobich e8aa034
Update processing order comment for clarity
JoeRobich 11be928
Rely on KnownUIContexts for whether a build is active
JoeRobich 43b5ded
Add comment and remove default button from dialog
JoeRobich 7ec935b
Simplify UnusedReferencesDataSource
JoeRobich ea0e2dc
Update tests to use Assert.Single
JoeRobich f603c6c
Make UnusedReferencesService a static class
JoeRobich 42bd41b
Throw unexpected value exception from ColumnDefinitions
JoeRobich 4e292c3
Add error handling to ProjectAssetsReader
JoeRobich 05dad08
Don't show dialog if operation is cancelled by user
JoeRobich 76ddc8e
Remove unused method
JoeRobich c82eb9c
Add nullability attribute
JoeRobich 096736d
Check that feature is enabled and pass TFM when getting project
JoeRobich c9fa026
Refactor responsibilities between the Table and Dialog providers.
JoeRobich 3c00635
Merge branch 'features/UsedAssemblyReferences' into add-unusedreferen…
JoeRobich 1115ec9
Merge remote-tracking branch 'origin/features/UsedAssemblyReferences'…
JoeRobich 03f3b23
Add an experiment to dogfood remove unused references
JoeRobich 6b5efb6
Rename UnusedReferencesService to UnusedReferencesRemover
JoeRobich 292bb6e
Use WhereNotNull() instread of OfType<>()
JoeRobich 1e744b4
Remove argument to IsBuildActive
JoeRobich 772a24a
Ensure we cleanup table data after showing dialog
JoeRobich 63c782e
Don't remove table entries in the Dispose() call.
JoeRobich b4a71c3
Be defensive about potentially removed projects
JoeRobich a886836
Add missing paren
JoeRobich 235c045
Fix test for new 2 pass behavior
JoeRobich 473155a
Fix formatting
JoeRobich File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
185 changes: 185 additions & 0 deletions
185
src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Test.Utilities; | ||
using Microsoft.CodeAnalysis.UnusedReferences; | ||
using Xunit; | ||
|
||
namespace Microsoft.CodeAnalysis.Editor.UnitTests.UnusedReferences | ||
{ | ||
public class UnusedReferencesRemoverTests | ||
{ | ||
private const string UsedAssemblyPath = "/libs/Used.dll"; | ||
private const string UnusedAssemblyPath = "/libs/Unused.dll"; | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public void GetUnusedReferences_UsedReferences_AreNotReturned() | ||
{ | ||
var usedAssemblies = new[] { UsedAssemblyPath }; | ||
var usedReference = AssemblyReference(UsedAssemblyPath); | ||
|
||
var unusedReferences = GetUnusedReferences(usedAssemblies, usedReference); | ||
|
||
Assert.Empty(unusedReferences); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public void GetUnusedReferences_UnusedReferences_AreReturned() | ||
{ | ||
var usedAssemblies = new[] { UsedAssemblyPath }; | ||
var unusedReference = PackageReference(UnusedAssemblyPath); | ||
|
||
var unusedReferences = GetUnusedReferences(usedAssemblies, unusedReference); | ||
|
||
Assert.Contains(unusedReference, unusedReferences); | ||
Assert.Single(unusedReferences); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public void GetUnusedReferences_TransitivelyUsedReferences_AreNotReturned() | ||
{ | ||
var usedAssemblies = new[] { UsedAssemblyPath }; | ||
var transitivelyUsedReference = ProjectReference(UnusedAssemblyPath, PackageReference(UsedAssemblyPath)); | ||
|
||
var unusedReferences = GetUnusedReferences(usedAssemblies, transitivelyUsedReference); | ||
|
||
Assert.Empty(unusedReferences); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public void GetUnusedReferences_WhenUsedAssemblyIsAvilableDirectlyAndTransitively_DirectReferencesAreReturned() | ||
{ | ||
var usedAssemblies = new[] { UsedAssemblyPath }; | ||
var transitivelyUsedReference = ProjectReference(UnusedAssemblyPath, PackageReference(UsedAssemblyPath)); | ||
var directlyUsedReference = PackageReference(UsedAssemblyPath); | ||
|
||
var unusedReferences = GetUnusedReferences(usedAssemblies, transitivelyUsedReference, directlyUsedReference); | ||
|
||
Assert.Contains(transitivelyUsedReference, unusedReferences); | ||
Assert.Single(unusedReferences); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public void GetUnusedReferences_ReferencesThatDoNotContributeToCompilation_AreNotReturned() | ||
{ | ||
var usedAssemblies = new[] { UsedAssemblyPath }; | ||
var analyzerReference = new ReferenceInfo( | ||
ReferenceType.Package, | ||
itemSpecification: "Analyzer", | ||
treatAsUsed: false, | ||
compilationAssemblies: ImmutableArray<string>.Empty, | ||
dependencies: ImmutableArray<ReferenceInfo>.Empty); | ||
|
||
var unusedReferences = GetUnusedReferences(usedAssemblies, analyzerReference); | ||
|
||
Assert.Empty(unusedReferences); | ||
} | ||
|
||
[Theory, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
[InlineData(UpdateAction.None, false)] | ||
[InlineData(UpdateAction.None, true)] | ||
[InlineData(UpdateAction.TreatAsUnused, false)] | ||
[InlineData(UpdateAction.TreatAsUsed, true)] | ||
internal async Task ApplyReferenceUpdates_NoChangeUpdates_AreNotApplied(UpdateAction action, bool treatAsUsed) | ||
{ | ||
var noChangeUpdate = new ReferenceUpdate(action, PackageReference(UnusedAssemblyPath, treatAsUsed)); | ||
|
||
var appliedUpdates = await ApplyReferenceUpdatesAsync(noChangeUpdate); | ||
|
||
Assert.Empty(appliedUpdates); | ||
} | ||
|
||
[Theory, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
[InlineData(UpdateAction.Remove, false)] | ||
[InlineData(UpdateAction.Remove, true)] | ||
[InlineData(UpdateAction.TreatAsUnused, true)] | ||
[InlineData(UpdateAction.TreatAsUsed, false)] | ||
internal async Task ApplyReferenceUpdates_ChangeUpdates_AreApplied(UpdateAction action, bool treatAsUsed) | ||
{ | ||
var changeUpdate = new ReferenceUpdate(action, PackageReference(UnusedAssemblyPath, treatAsUsed)); | ||
|
||
var appliedUpdates = await ApplyReferenceUpdatesAsync(changeUpdate); | ||
|
||
Assert.Contains(changeUpdate, appliedUpdates); | ||
Assert.Single(appliedUpdates); | ||
} | ||
|
||
[Fact, Trait(Traits.Feature, Traits.Features.UnusedReferences)] | ||
public async Task ApplyReferenceUpdates_MixOfChangeAndNoChangeUpdates_ChangesAreApplied() | ||
{ | ||
var noChangeUpdate = new ReferenceUpdate(UpdateAction.None, PackageReference(UsedAssemblyPath)); | ||
var changeUpdate = new ReferenceUpdate(UpdateAction.Remove, PackageReference(UnusedAssemblyPath)); | ||
|
||
var appliedUpdates = await ApplyReferenceUpdatesAsync(noChangeUpdate, changeUpdate); | ||
|
||
Assert.Contains(changeUpdate, appliedUpdates); | ||
Assert.Single(appliedUpdates); | ||
} | ||
|
||
private static ImmutableArray<ReferenceInfo> GetUnusedReferences(string[] usedCompilationAssemblies, params ReferenceInfo[] references) | ||
=> UnusedReferencesRemover.GetUnusedReferences(new(usedCompilationAssemblies), references.ToImmutableArray()); | ||
|
||
private static async Task<ImmutableArray<ReferenceUpdate>> ApplyReferenceUpdatesAsync(params ReferenceUpdate[] referenceUpdates) | ||
{ | ||
var referenceCleanupService = new TestReferenceCleanupService(); | ||
|
||
await UnusedReferencesRemover.ApplyReferenceUpdatesAsync( | ||
referenceCleanupService, | ||
string.Empty, | ||
referenceUpdates.ToImmutableArray(), | ||
CancellationToken.None).ConfigureAwait(false); | ||
|
||
return referenceCleanupService.AppliedUpdates.ToImmutableArray(); | ||
} | ||
|
||
private static ReferenceInfo ProjectReference(string assemblyPath, params ReferenceInfo[] dependencies) | ||
=> ProjectReference(assemblyPath, treatAsUsed: false, dependencies); | ||
private static ReferenceInfo ProjectReference(string assemblyPath, bool treatAsUsed, params ReferenceInfo[] dependencies) | ||
=> new(ReferenceType.Project, | ||
itemSpecification: Path.GetFileName(assemblyPath), | ||
treatAsUsed, | ||
compilationAssemblies: ImmutableArray.Create(assemblyPath), | ||
dependencies.ToImmutableArray()); | ||
|
||
private static ReferenceInfo PackageReference(string assemblyPath, params ReferenceInfo[] dependencies) | ||
=> PackageReference(assemblyPath, treatAsUsed: false, dependencies); | ||
private static ReferenceInfo PackageReference(string assemblyPath, bool treatAsUsed, params ReferenceInfo[] dependencies) | ||
=> new(ReferenceType.Package, | ||
itemSpecification: Path.GetFileName(assemblyPath), | ||
treatAsUsed, | ||
compilationAssemblies: ImmutableArray.Create(assemblyPath), | ||
dependencies.ToImmutableArray()); | ||
|
||
private static ReferenceInfo AssemblyReference(string assemblyPath) | ||
=> AssemblyReference(assemblyPath, treatAsUsed: false); | ||
private static ReferenceInfo AssemblyReference(string assemblyPath, bool treatAsUsed) | ||
=> new(ReferenceType.Assembly, | ||
itemSpecification: Path.GetFileName(assemblyPath), | ||
treatAsUsed, | ||
compilationAssemblies: ImmutableArray.Create(assemblyPath), | ||
dependencies: ImmutableArray<ReferenceInfo>.Empty); | ||
|
||
private class TestReferenceCleanupService : IReferenceCleanupService | ||
{ | ||
private readonly List<ReferenceUpdate> _appliedUpdates = new(); | ||
public IReadOnlyList<ReferenceUpdate> AppliedUpdates => _appliedUpdates; | ||
|
||
public Task<ImmutableArray<ReferenceInfo>> GetProjectReferencesAsync(string projectPath, CancellationToken cancellationToken) | ||
{ | ||
throw new System.NotImplementedException(); | ||
} | ||
|
||
public Task<bool> TryUpdateReferenceAsync(string projectPath, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken) | ||
{ | ||
_appliedUpdates.Add(referenceUpdate); | ||
return Task.FromResult(true); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 0 additions & 31 deletions
31
src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentinoally not taking a Project object here, since it's returning it for all possible targets at once?