From b90c7771475c017c41cf4e2c9f76c562811aff70 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 17:05:09 -0800 Subject: [PATCH 01/57] Cleanup ReferenceCleanupService --- .../IReferenceCleanupService.cs | 15 ------- .../VisualStudioReferenceCleanupService.cs | 44 +++---------------- 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs b/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs index e415a1adf99d8..037056a74f360 100644 --- a/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs +++ b/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs @@ -13,26 +13,12 @@ namespace Microsoft.CodeAnalysis.UnusedReferences { internal interface IReferenceCleanupService : IWorkspaceService { - /// - /// Gets the current selected TargetFrameworkMoniker for the specified project. - /// - string GetTargetFrameworkMoniker(ProjectId projectId); - - /// - /// For the given project, returns the full path to the project.assets.json file - /// generated in the intermediate output path by a NuGet restore. - /// - Task GetProjectAssetsFilePathAsync( - string projectPath, - CancellationToken cancellationToken); - /// /// Return the set of direct Project and Package references for the given project. This /// is used to get the initial state of the TreatAsUsed attribute for each reference. /// Task> GetProjectReferencesAsync( string projectPath, - string targetFrameworkMoniker, CancellationToken cancellationToken); /// @@ -42,7 +28,6 @@ Task> GetProjectReferencesAsync( /// True, if the reference was updated. Task TryUpdateReferenceAsync( string projectPath, - string targetFrameworkMoniker, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken); } diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs index 15340ecd00407..11eb1be0f1b69 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs @@ -10,11 +10,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.ProjectSystem.Api; -using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences { @@ -25,55 +23,23 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReference internal sealed class VisualStudioReferenceCleanupService : IReferenceCleanupService { private readonly IProjectSystemReferenceCleanupService _projectSystemReferenceUpdateService; - private readonly VisualStudioWorkspaceImpl _workspace; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioReferenceCleanupService( - IProjectSystemReferenceCleanupService projectSystemReferenceUpdateService, - VisualStudioWorkspaceImpl workspace) + public VisualStudioReferenceCleanupService(IProjectSystemReferenceCleanupService projectSystemReferenceUpdateService) { _projectSystemReferenceUpdateService = projectSystemReferenceUpdateService; - _workspace = workspace; } - public string GetTargetFrameworkMoniker(ProjectId projectId) + public async Task> GetProjectReferencesAsync(string projectPath, CancellationToken cancellationToken) { - if (_workspace.TryGetHierarchy(projectId, out var hierarchy) && - hierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out var targetFrameworkMoniker)) - { - return targetFrameworkMoniker ?? string.Empty; - } - - return string.Empty; - } - - public Task GetProjectAssetsFilePathAsync(string projectPath, CancellationToken cancellationToken) - { -#if false // PROTOTYPE: Temporary disabling code causing a build break - return _projectSystemReferenceUpdateService.GetProjectAssetsFilePathAsync(projectPath, cancellationToken); -#else - return Task.FromResult(""); -#endif - } - - public async Task> GetProjectReferencesAsync(string projectPath, string targetFramework, CancellationToken cancellationToken) - { -#if false // PROTOTYPE: Temporary disabling code causing a build break - var projectSystemReferences = await _projectSystemReferenceUpdateService.GetProjectReferencesAsync(projectPath, targetFramework, cancellationToken).ConfigureAwait(false); + var projectSystemReferences = await _projectSystemReferenceUpdateService.GetProjectReferencesAsync(projectPath, cancellationToken).ConfigureAwait(false); return projectSystemReferences.Select(reference => reference.ToReferenceInfo()).ToImmutableArray(); -#else - return await Task>.FromResult(ImmutableArray.Empty).ConfigureAwait(false); -#endif } - public Task TryUpdateReferenceAsync(string projectPath, string targetFramework, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken) + public Task TryUpdateReferenceAsync(string projectPath, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken) { -#if false // PROTOTYPE: Temporary disabling code causing a build break - return _projectSystemReferenceUpdateService.TryUpdateReferenceAsync(projectPath, targetFramework, referenceUpdate.ToProjectSystemReferenceUpdate(), cancellationToken); -#else - return Task.FromResult(false); -#endif + return _projectSystemReferenceUpdateService.TryUpdateReferenceAsync(projectPath, referenceUpdate.ToProjectSystemReferenceUpdate(), cancellationToken); } } } From 655c15849ed9b18b8be6cd2d25debc3705144008 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 17:07:44 -0800 Subject: [PATCH 02/57] Add UnusedReferenceService to determine unused references --- .../IUnusedReferencesService.cs | 6 +- .../UnusedReferences/ReferenceInfo.cs | 40 +++++- .../UnusedReferencesService.cs | 132 ++++++++++++++++++ .../UnusedReferenceExtensions.cs | 22 +-- 4 files changed, 189 insertions(+), 11 deletions(-) create mode 100644 src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs diff --git a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs index eeb2c0ed8fe22..314ea80ff1e89 100644 --- a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -12,10 +14,12 @@ namespace Microsoft.CodeAnalysis.UnusedReferences internal interface IUnusedReferencesService : IWorkspaceService { /// - /// Determines unused references from this compilation. + /// Determines unused references for this project. /// Task> GetUnusedReferencesAsync( Project project, + ImmutableArray references, + string targetFrameworkMoniker, CancellationToken cancellationToken); /// diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index 894a17cd76fe4..b79e10ef0b70c 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -2,10 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + namespace Microsoft.CodeAnalysis.UnusedReferences { internal class ReferenceInfo { + private ImmutableArray? _allCompilationAssemblies; + /// /// Indicates the type of reference. /// @@ -24,11 +32,41 @@ internal class ReferenceInfo /// public bool TreatAsUsed { get; } - public ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool treatAsUsed) + /// + /// The assembly paths that this reference directly adds to the compilation. + /// + public ImmutableArray CompilationAssemblies { get; } + + /// + /// The dependencies that this reference transitively brings in to the compilation. + /// + public ImmutableArray Dependencies { get; } + + public ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool treatAsUsed, ImmutableArray compilationAssemblies, ImmutableArray dependencies) { ReferenceType = referenceType; ItemSpecification = itemSpecification; TreatAsUsed = treatAsUsed; + CompilationAssemblies = compilationAssemblies; + Dependencies = dependencies; + } + + /// + /// Gets the compilation assemblies this reference directly brings into the compilation as well as those + /// brought in transitively. + /// + public ImmutableArray GetAllCompilationAssemblies() + { + _allCompilationAssemblies ??= CompilationAssemblies + .Concat(GetTransitiveCompilationAssemblies()) + .ToImmutableArray(); + + return _allCompilationAssemblies.Value; + } + + private IEnumerable GetTransitiveCompilationAssemblies() + { + return Dependencies.SelectMany(dependency => dependency.GetAllCompilationAssemblies()); } } } diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs new file mode 100644 index 0000000000000..72b0d4e0d4a54 --- /dev/null +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -0,0 +1,132 @@ +// 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. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.UnusedReferences +{ + [ExportWorkspaceService(typeof(IUnusedReferencesService), ServiceLayer.Default), Shared] + internal class UnusedReferencesService : IUnusedReferencesService + { + private readonly ReferenceType[] _processingOrder = new[] { ReferenceType.Project, ReferenceType.Package, ReferenceType.Assembly }; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UnusedReferencesService() + { + + } + + public async Task> GetUnusedReferencesAsync( + Project project, + ImmutableArray references, + string targetFrameworkMoniker, + CancellationToken cancellationToken) + { + // Create a lookup of used assembly paths + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken).Select(reference => reference.Display); + var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); + + var unusedReferences = ImmutableArray.CreateBuilder(); + var referencesByType = references.GroupBy(reference => reference.ReferenceType).ToImmutableDictionary(group => group.Key); + + foreach (var referenceType in _processingOrder) + { + if (!referencesByType.ContainsKey(referenceType)) + { + continue; + } + + usedAssemblyReferences = DetermineUnusedReferences(referencesByType[referenceType], usedAssemblyReferences, unusedReferences); + } + + return unusedReferences.ToImmutableArray(); + } + + private static IEnumerable DetermineUnusedReferences(IEnumerable references, IEnumerable usedAssemblyReferences, ImmutableArray.Builder unusedReferences) + { + var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); + + // Determine which toplevel references have compilation assemblies in set of used assemblies. + var toplevelUsedReferences = references.Where(reference => + reference.CompilationAssemblies.Any(assembly => usedAssemblyLookup.Contains(assembly))); + var toplevelUsedAssemblyReferences = toplevelUsedReferences.SelectMany(reference => reference.GetAllCompilationAssemblies()); + + // Remove all assemblies that are brought into the compilation from the toplevel used references. When + // determining transtively used references this will reduce false positives. + var remainingReferences = references.Except(toplevelUsedReferences); + var remainingUsedAssemblyReferences = usedAssemblyReferences.Except(toplevelUsedAssemblyReferences); + var remainingUsedAssemblyLookup = remainingUsedAssemblyReferences.ToImmutableHashSet(); + + // Determine which transtive references have compilation assemblies in the set of remaining used assemblies. + foreach (var reference in remainingReferences) + { + var allCompilationAssemblies = reference.GetAllCompilationAssemblies(); + if (allCompilationAssemblies.IsEmpty) + { + // Analyzer packages won't contribute any assemblies to the compilation but will + // show up as a reference. We will consider them used. + continue; + } + + if (!allCompilationAssemblies.Any(assembly => remainingUsedAssemblyLookup.Contains(assembly))) + { + // References that do not contribute a used compilation assembly are considered unsused. + unusedReferences.Add(reference); + continue; + } + + remainingUsedAssemblyReferences = remainingUsedAssemblyReferences.Except(allCompilationAssemblies); + remainingUsedAssemblyLookup = remainingUsedAssemblyReferences.ToImmutableHashSet(); + } + + return remainingUsedAssemblyReferences; + } + + public async Task UpdateReferencesAsync(Project project, ImmutableArray referenceUpdates, CancellationToken cancellationToken) + { + var referenceCleanupService = project.Solution.Workspace.Services.GetRequiredService(); + + // Remove unused usings + + foreach (var referenceUpdate in referenceUpdates) + { + if (referenceUpdate.Action == UpdateAction.None) + { + referenceUpdate.Action = referenceUpdate.ReferenceInfo.TreatAsUsed + ? UpdateAction.TreatAsUnused + : UpdateAction.None; + } + else if (referenceUpdate.Action == UpdateAction.TreatAsUsed) + { + referenceUpdate.Action = referenceUpdate.ReferenceInfo.TreatAsUsed + ? UpdateAction.None + : UpdateAction.TreatAsUsed; + } + + if (referenceUpdate.Action == UpdateAction.None) + { + continue; + } + + await referenceCleanupService.TryUpdateReferenceAsync( + project.FilePath, + referenceUpdate, + cancellationToken).ConfigureAwait(true); + } + + return project; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs index eadd224880927..8ecab4288f15e 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs @@ -4,32 +4,36 @@ #nullable enable +using System.Collections.Immutable; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.ProjectSystem.Api; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences { internal static class UnusedReferenceExtensions { - public static ReferenceUpdate ToReferenceUpdate(this ProjectSystemReferenceUpdate projectSystemReferenceUpdate) - { - return new ReferenceUpdate( - (UpdateAction)projectSystemReferenceUpdate.Action, - projectSystemReferenceUpdate.ReferenceInfo.ToReferenceInfo()); - } - public static ReferenceInfo ToReferenceInfo(this ProjectSystemReferenceInfo projectSystemReference) { return new ReferenceInfo( (ReferenceType)projectSystemReference.ReferenceType, projectSystemReference.ItemSpecification, - projectSystemReference.TreatAsUsed); + projectSystemReference.TreatAsUsed, + ImmutableArray.Empty, + ImmutableArray.Empty); } public static ProjectSystemReferenceUpdate ToProjectSystemReferenceUpdate(this ReferenceUpdate referenceUpdate) { + var updateAction = referenceUpdate.Action switch + { + UpdateAction.TreatAsUsed => ProjectSystemUpdateAction.SetTreatAsUsed, + UpdateAction.TreatAsUnused => ProjectSystemUpdateAction.UnsetTreatAsUsed, + UpdateAction.Remove => ProjectSystemUpdateAction.Remove, + _ => throw ExceptionUtilities.Unreachable + }; return new ProjectSystemReferenceUpdate( - (ProjectSystemUpdateAction)referenceUpdate.Action, + updateAction, referenceUpdate.ReferenceInfo.ToProjectSystemReferenceInfo()); } From 93e4bb15543e922a015f43dbc8d92ec0b6ce1c7e Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 17:08:32 -0800 Subject: [PATCH 03/57] Add ProjectAssets model and reader --- .../ProjectAssets/ProjectAssetsModel.cs | 63 +++++++++ .../ProjectAssets/ProjectAssetsReader.cs | 126 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs new file mode 100644 index 0000000000000..121f40033685c --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs @@ -0,0 +1,63 @@ +// 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. + +#nullable enable + +using System.Collections.Generic; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets +{ + // These classes model enough of the version 3 project.assets.json file that we can + // parse out the dependency tree and compilation assemblies that each reference brings + // in to the project. + + internal class ProjectAssetsFile + { + public int Version { get; set; } + public Dictionary>? Targets { get; set; } + public Dictionary? Libraries { get; set; } + public Dictionary>? ProjectFileDependencyGroups { get; set; } + public ProjectAssetsProject? Project { get; set; } + } + + internal class ProjectAssetsTargetLibrary + { + public string? Type { get; set; } + public Dictionary? Dependencies { get; set; } + public Dictionary? Compile { get; set; } + } + + internal class ProjectAssetsTargetLibraryCompile + { + + } + + internal class ProjectAssetsLibrary + { + public string? Path { get; set; } + } + + internal class ProjectAssetsProject + { + public ProjectAssetsProjectRestore? Restore { get; set; } + public Dictionary? Frameworks { get; set; } + } + + internal class ProjectAssetsProjectRestore + { + public string? ProjectPath { get; set; } + public string? PackagesPath { get; set; } + } + + internal class ProjectAssetsProjectFramework + { + public string? TargetAlias { get; set; } + public Dictionary? Dependencies { get; set; } + } + + internal class ProjectAssetsProjectFrameworkDependency + { + public bool AutoReferenced { get; set; } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs new file mode 100644 index 0000000000000..c3b70f9561428 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs @@ -0,0 +1,126 @@ +// 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. + +#nullable enable + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis.UnusedReferences; +using Newtonsoft.Json; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets +{ + // This class will read the dependency heirarchy from the project.assets.json file. The format of this file + // is subject to change and in the future this information will be provided by an API with the ProjectSystem. + internal static class ProjectAssetsReader + { + public static ImmutableArray ReadReferences( + ImmutableArray projectReferences, + string projectAssetsFilePath, + string targetFrameworkMoniker) + { + var projectAssetsFileContents = File.ReadAllText(projectAssetsFilePath); + var projectAssets = JsonConvert.DeserializeObject(projectAssetsFileContents); + + if (projectAssets is null || + projectAssets.Version != 3) + { + return ImmutableArray.Empty; + } + + if (projectAssets.Targets is null || + !projectAssets.Targets.TryGetValue(targetFrameworkMoniker, out var target)) + { + return ImmutableArray.Empty; + } + + var autoReferences = projectAssets.Project?.Frameworks?.Values + .SelectMany(framework => framework.Dependencies?.Keys.Where(key => framework.Dependencies[key].AutoReferenced)) + .Distinct() + .ToImmutableHashSet(); + autoReferences ??= ImmutableHashSet.Empty; + + var references = projectReferences + .Select(projectReference => BuildReference(projectAssets, target, projectReference, autoReferences)) + .OfType() + .ToImmutableArray(); + + return references; + } + + private static ReferenceInfo? BuildReference( + ProjectAssetsFile projectAssets, + Dictionary target, + ReferenceInfo projectReference, + ImmutableHashSet autoReferences) + { + var referenceName = projectReference.ReferenceType == ReferenceType.Project + ? Path.GetFileNameWithoutExtension(projectReference.ItemSpecification) + : projectReference.ItemSpecification; + + if (autoReferences.Contains(referenceName)) + { + return null; + } + + return BuildReference(projectAssets, target, referenceName, projectReference.TreatAsUsed); + } + + private static ReferenceInfo? BuildReference( + ProjectAssetsFile projectAssets, + Dictionary target, + string dependency, + bool treatAsUsed) + { + var key = target.Keys.FirstOrDefault(library => library.Split('/')[0] == dependency); + if (key is null) + { + return null; + } + + return BuildReference(projectAssets, target, dependency, treatAsUsed, key, target[key]); + } + + private static ReferenceInfo? BuildReference( + ProjectAssetsFile projectAssets, + Dictionary target, + string referenceName, + bool treatAsUsed, + string key, + ProjectAssetsTargetLibrary targetLibrary) + { + if (projectAssets.Libraries is null || + !projectAssets.Libraries.TryGetValue(key, out var library)) + { + return null; + } + + var type = targetLibrary.Type switch + { + "package" => ReferenceType.Package, + "project" => ReferenceType.Project, + _ => ReferenceType.Assembly + }; + + var dependencies = targetLibrary.Dependencies != null + ? targetLibrary.Dependencies.Keys + .Select(dependency => BuildReference(projectAssets, target, dependency, treatAsUsed: false)) + .OfType() + .ToImmutableArray() + : ImmutableArray.Empty; + + var packagesPath = projectAssets.Project?.Restore?.PackagesPath ?? string.Empty; + var compilationAssemblies = targetLibrary.Compile != null + ? targetLibrary.Compile.Keys + .Where(assemblyPath => !assemblyPath.EndsWith("_._")) + .Select(assemblyPath => Path.GetFullPath(Path.Combine(packagesPath, library.Path, assemblyPath))) + .ToImmutableArray() + : ImmutableArray.Empty; + + return new ReferenceInfo(type, referenceName, treatAsUsed, compilationAssemblies, dependencies); + } + } +} From 98f10c7477a05dc41f74effefc2f7e527d7ee3f7 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 16:59:28 -0800 Subject: [PATCH 04/57] Add string resources --- .../Core/Def/ServicesVSResources.resx | 38 +++++++++++- .../Core/Def/xlf/ServicesVSResources.cs.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.de.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.es.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.fr.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.it.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.ja.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.ko.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.pl.xlf | 60 +++++++++++++++++++ .../Def/xlf/ServicesVSResources.pt-BR.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.ru.xlf | 60 +++++++++++++++++++ .../Core/Def/xlf/ServicesVSResources.tr.xlf | 60 +++++++++++++++++++ .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 60 +++++++++++++++++++ .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 60 +++++++++++++++++++ 14 files changed, 817 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 6090e6ca5de8f..1ed7788ad0072 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1,4 +1,4 @@ - + - + + "ECMD_RUNFXCOPSEL" is actually defined in stdidcmd.h, we're just referencing it here --> - - + + + + @@ -437,7 +459,7 @@ Set severity - + @@ -495,6 +517,10 @@ + + + + @@ -557,7 +583,7 @@ - + @@ -578,6 +604,9 @@ + + + diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf index 646c47c36abc1..c801ac1d10632 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis Spustit &analýzu kódu diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf index 82dc17d6fbeb1..23eff5dbf00f4 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis C&ode Analysis ausführen diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf index 3a230f73e861b..3ce74cad111b2 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis E&jecutar análisis de código diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf index 5d3bb3bad0423..af010ccfe550c 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis Exécuter l'analyse du c&ode diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf index 9ab4f9ab9da30..3ae170a22779a 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis Esegui C&ode Analysis diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf index 1d329b634a821..caf5f517e7d24 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis コード分析の実行(&O) diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf index a52578e81d8d7..aed9a73b5036b 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis 코드 분석 실행(&O) diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf index ebcca12449dcb..6feb5eba39b32 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis Uru&chom analizę kodu diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf index 27de984854c8e..64b93066817b8 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis Executar Análise de Códig&o diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf index b08555c8f680e..efaefa96935d1 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis &Запустить анализ кода diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf index 0f66c44e7250b..4c8a4a9ad847f 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis K&od Analizini Çalıştır diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf index 955e404135e8a..41227b0ad15c7 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis 运行代码分析(&O) diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf index e94838d852490..bcfe9f13a228d 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf @@ -212,6 +212,21 @@ OpenActiveRuleSet + + Remove &Unused References + Remove &Unused References + + + + RemoveUnusedReferences + RemoveUnusedReferences + + + + RemoveUnusedReferences + RemoveUnusedReferences + + Run C&ode Analysis 執行程式碼分析(&O) From d0130fbcddb36245ba9e4644c123f230baf3a94b Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 17:11:54 -0800 Subject: [PATCH 08/57] Add command handler for the remove unused references command --- .../Core/Def/ID.RoslynCommands.cs | 1 + .../RemoveUnusedReferencesCommandHandler.cs | 300 ++++++++++++++++++ src/VisualStudio/Core/Def/RoslynPackage.cs | 2 + 3 files changed, 303 insertions(+) create mode 100644 src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs diff --git a/src/VisualStudio/Core/Def/ID.RoslynCommands.cs b/src/VisualStudio/Core/Def/ID.RoslynCommands.cs index 6a4bc42f21f25..d89285327286e 100644 --- a/src/VisualStudio/Core/Def/ID.RoslynCommands.cs +++ b/src/VisualStudio/Core/Def/ID.RoslynCommands.cs @@ -49,6 +49,7 @@ public static class RoslynCommands public const int GoToImplementation = 0x0200; public const int RunCodeAnalysisForProject = 0x0201; + public const int RemoveUnusedReferences = 0x0202; } } } diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs new file mode 100644 index 0000000000000..f624149163486 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -0,0 +1,300 @@ +// 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. + +#nullable enable + +using System; +using System.Collections.Immutable; +using System.ComponentModel.Design; +using System.Composition; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows; +using System.Windows.Interop; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.UnusedReferences; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; +using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.Dialog; +using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences +{ + [Export(typeof(RemoveUnusedReferencesCommandHandler)), Shared] + internal sealed class RemoveUnusedReferencesCommandHandler + { + private const string ProjectAssetsFilePropertyName = "ProjectAssetsFile"; + + private readonly IReferenceCleanupService _referenceCleanupService; + private readonly IUnusedReferencesService _unusedReferencesService; + private readonly RemoveUnusedReferencesDialogProvider _unusedReferenceDialogProvider; + private readonly VisualStudioWorkspaceImpl _workspace; + private readonly IVsHierarchyItemManager _vsHierarchyItemManager; + private readonly IUIThreadOperationExecutor _threadOperationExecutor; + private IServiceProvider? _serviceProvider; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RemoveUnusedReferencesCommandHandler( + RemoveUnusedReferencesDialogProvider unusedReferenceDialogProvider, + IVsHierarchyItemManager vsHierarchyItemManager, + IUIThreadOperationExecutor threadOperationExecutor, + VisualStudioWorkspaceImpl workspace) + { + _unusedReferenceDialogProvider = unusedReferenceDialogProvider; + _vsHierarchyItemManager = vsHierarchyItemManager; + _threadOperationExecutor = threadOperationExecutor; + _workspace = workspace; + + _referenceCleanupService = workspace.Services.GetRequiredService(); + _unusedReferencesService = workspace.Services.GetRequiredService(); + } + + public void Initialize(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + + Contract.ThrowIfNull(_serviceProvider); + + // Hook up the "Run Code Analysis" menu command for CPS based managed projects. + var menuCommandService = (IMenuCommandService)_serviceProvider.GetService(typeof(IMenuCommandService)); + if (menuCommandService != null) + { + AddCommand(menuCommandService, ID.RoslynCommands.RemoveUnusedReferences, Guids.RoslynGroupId, OnRemoveUnusedReferencesForSelectedProject, OnRemoveUnusedReferencesForSelectedProjectStatus); + } + + return; + + // Local functions + static OleMenuCommand AddCommand( + IMenuCommandService menuCommandService, + int commandId, + Guid commandGroup, + EventHandler invokeHandler, + EventHandler beforeQueryStatus) + { + var commandIdWithGroupId = new CommandID(commandGroup, commandId); + var command = new OleMenuCommand(invokeHandler, delegate { }, beforeQueryStatus, commandIdWithGroupId); + menuCommandService.AddCommand(command); + return command; + } + } + + private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, EventArgs e) + { + var command = (OleMenuCommand)sender; + + // We hook up the "Run Code Analysis" menu commands for CPS based managed projects. + // These commands are already hooked up for csproj based projects in StanCore, but those will eventually go away. + var visible = TryGetSelectedProjectHierarchy(out var hierarchy) && + hierarchy.IsCapabilityMatch("CPS") && + hierarchy.IsCapabilityMatch(".NET"); + var enabled = false; + + if (visible) + { + if (hierarchy!.TryGetProject(out _)) + { + // Change to show the name of the project as part of the menu item display text. + // command.Text = string.Format("Remove Unused References for {0}", project!.Name); + } + + enabled = !IsBuildActive(); + } + + if (command.Visible != visible) + { + command.Visible = visible; + } + if (command.Enabled != enabled) + { + command.Enabled = enabled; + } + } + + private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs args) + { + if (TryGetSelectedProjectHierarchy(out var hierarchy)) + { + Project? project = null; + ImmutableArray referenceUpdates; + _threadOperationExecutor.Execute(ServicesVSResources.Remove_Unused_References, ServicesVSResources.Analyzing_project_references, allowCancellation: true, showProgress: true, (operationContext) => + { + (project, referenceUpdates) = GetUnusedReferencesForProjectHierarchy(hierarchy, operationContext.UserCancellationToken); + }); + + if (project is null || + referenceUpdates.IsEmpty) + { + return; + } + + var dialog = GetUnusedReferencesDialog(project, referenceUpdates); + if (dialog.ShowDialog() == false) + { + return; + } + + _threadOperationExecutor.Execute(ServicesVSResources.Remove_Unused_References, ServicesVSResources.Updating_project_references, allowCancellation: false, showProgress: true, (operationContext) => + { + ApplyUnusedReferenceUpdates(project, referenceUpdates, CancellationToken.None); + }); + } + + return; + } + + private (Project?, ImmutableArray) GetUnusedReferencesForProjectHierarchy(IVsHierarchy projectHierarchy, CancellationToken cancellationToken) + { + if (!TryGetPropertyValue(projectHierarchy, ProjectAssetsFilePropertyName, out var projectAssetsFile) || + !projectHierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out var targetFrameworkMoniker)) + { + return (null, ImmutableArray.Empty); + } + + var projectMap = _workspace.Services.GetRequiredService(); + var projectHierarchyItem = _vsHierarchyItemManager.GetHierarchyItem(projectHierarchy, VSConstants.VSITEMID_ROOT); + + if (!projectMap.TryGetProjectId(projectHierarchyItem, targetFrameworkMoniker: null, out var projectId)) + { + return (null, ImmutableArray.Empty); + } + + var project = _workspace.CurrentSolution.GetProject(projectId)!; + var unusedReferences = GetUnusedReferencesForProject(project, projectAssetsFile!, targetFrameworkMoniker, cancellationToken); + + return (project, unusedReferences); + } + + private ImmutableArray GetUnusedReferencesForProject(Project project, string projectAssetsFile, string targetFrameworkMoniker, CancellationToken cancellationToken) + { + ImmutableArray unusedReferences = ThreadHelper.JoinableTaskFactory.Run(async () => + { + var projectReferences = await _referenceCleanupService.GetProjectReferencesAsync(project.FilePath, cancellationToken).ConfigureAwait(true); + var references = ProjectAssetsReader.ReadReferences(projectReferences, projectAssetsFile, targetFrameworkMoniker); + + return await _unusedReferencesService.GetUnusedReferencesAsync(project, references, targetFrameworkMoniker, cancellationToken).ConfigureAwait(true); + }); + + var referenceUpdates = unusedReferences + .Select(reference => new ReferenceUpdate(reference.TreatAsUsed ? UpdateAction.TreatAsUsed : UpdateAction.Remove, reference)) + .ToImmutableArray(); + + return referenceUpdates; + } + + private Window GetUnusedReferencesDialog(Project project, ImmutableArray referenceUpdates) + { + var uiShell = _serviceProvider.GetService(); + uiShell.GetDialogOwnerHwnd(out var ownerHwnd); + + var dialog = _unusedReferenceDialogProvider.CreateDialog(project, referenceUpdates); + + var windowHelper = new WindowInteropHelper(dialog) + { + Owner = ownerHwnd + }; + + uiShell.CenterDialogOnWindow(windowHelper.Handle, IntPtr.Zero); + + return dialog; + } + + private void ApplyUnusedReferenceUpdates(Project project, ImmutableArray referenceUpdates, CancellationToken cancellationToken) + { + ThreadHelper.JoinableTaskFactory.Run( + () => _unusedReferencesService.UpdateReferencesAsync(project, referenceUpdates, cancellationToken)); + } + + private static bool TryGetPropertyValue(IVsHierarchy hierarchy, string propertyName, out string? propertyValue) + { + if (hierarchy is not IVsBuildPropertyStorage storage) + { + propertyValue = null; + return false; + } + + return ErrorHandler.Succeeded(storage.GetPropertyValue(propertyName, null, (uint)_PersistStorageType.PST_PROJECT_FILE, out propertyValue)); + } + + private bool TryGetSelectedProjectHierarchy([NotNullWhen(returnValue: true)] out IVsHierarchy? hierarchy) + { + hierarchy = null; + + // Get the DTE service and make sure there is an open solution + if (_serviceProvider?.GetService(typeof(EnvDTE.DTE)) is not EnvDTE.DTE dte || + dte.Solution == null) + { + return false; + } + + var selectionHierarchy = IntPtr.Zero; + var selectionContainer = IntPtr.Zero; + + // Get the current selection in the shell + if (_serviceProvider.GetService(typeof(SVsShellMonitorSelection)) is IVsMonitorSelection monitorSelection) + { + try + { + monitorSelection.GetCurrentSelection(out selectionHierarchy, out var itemId, out var multiSelect, out selectionContainer); + if (selectionHierarchy != IntPtr.Zero) + { + hierarchy = Marshal.GetObjectForIUnknown(selectionHierarchy) as IVsHierarchy; + Debug.Assert(hierarchy != null); + return hierarchy != null; + } + } + catch (Exception) + { + // If anything went wrong, just ignore it + } + finally + { + // Make sure we release the COM pointers in any case + if (selectionHierarchy != IntPtr.Zero) + { + Marshal.Release(selectionHierarchy); + } + + if (selectionContainer != IntPtr.Zero) + { + Marshal.Release(selectionContainer); + } + } + } + + return false; + } + + private bool IsBuildActive() + { + // Using KnownUIContexts is faster in case when SBM's package was not loaded yet + if (KnownUIContexts.SolutionBuildingContext != null) + { + return KnownUIContexts.SolutionBuildingContext.IsActive; + } + else + { + // Unlikely case that above service is not available, let's try Solution Build Manager + if (_serviceProvider?.GetService(typeof(SVsSolutionBuildManager)) is IVsSolutionBuildManager buildManager) + { + buildManager.QueryBuildManagerBusy(out var buildBusy); + return buildBusy != 0; + } + else + { + Debug.Fail("Unable to determine whether build is active or not"); + return true; + } + } + } + } +} diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 8269895e599f1..7261ce5c45d59 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -35,6 +35,7 @@ using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetry; using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource; using Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments; +using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.Telemetry; using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; @@ -180,6 +181,7 @@ protected override async Task LoadComponentsAsync(CancellationToken cancellation this.ComponentModel.GetService().Initialize(this); this.ComponentModel.GetService().Initialize(this); + this.ComponentModel.GetService().Initialize(this); LoadAnalyzerNodeComponents(); From 4cc3f122aa936cf568f02c8f1e7740f893aa223c Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 8 Dec 2020 17:21:21 -0800 Subject: [PATCH 09/57] Remove nullable pragmas --- .../Core/Portable/UnusedReferences/IReferenceCleanupService.cs | 2 -- .../Core/Portable/UnusedReferences/IUnusedReferencesService.cs | 2 -- src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs | 2 -- src/Features/Core/Portable/UnusedReferences/ReferenceUpdate.cs | 2 -- .../Core/Portable/UnusedReferences/UnusedReferencesService.cs | 2 -- .../Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs | 2 -- .../Dialog/UnusedReferencesTableProvider.DataSource.cs | 2 -- .../UnusedReferences/Dialog/UnusedReferencesTableProvider.cs | 2 -- .../UnusedReferences/ProjectAssets/ProjectAssetsModel.cs | 2 -- .../UnusedReferences/ProjectAssets/ProjectAssetsReader.cs | 2 -- .../UnusedReferences/RemoveUnusedReferencesCommandHandler.cs | 2 -- .../UnusedReferences/UnusedReferenceExtensions.cs | 2 -- .../UnusedReferences/VisualStudioReferenceCleanupService.cs | 2 -- 13 files changed, 26 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs b/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs index 037056a74f360..825edacd5ae37 100644 --- a/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs +++ b/src/Features/Core/Portable/UnusedReferences/IReferenceCleanupService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs index 314ea80ff1e89..6cbfdb1e1cc32 100644 --- a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index b79e10ef0b70c..1f660ed02cb66 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceUpdate.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceUpdate.cs index 45242e0bbec9a..4c7a4c0fbffe1 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceUpdate.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceUpdate.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - namespace Microsoft.CodeAnalysis.UnusedReferences { internal sealed class ReferenceUpdate diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 72b0d4e0d4a54..f4c21fe9cb822 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs index 0831f31c204fb..3fa4842f68f02 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.ComponentModel.Composition; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs index 693cf2518bec3..adbfb3fff88d3 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.DataSource.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.IO; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs index 75484e099b251..f5086b4707ed4 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.ComponentModel.Composition; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs index 121f40033685c..7a456e6dfc90a 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Generic; namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs index c3b70f9561428..17e3ffa21003a 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Generic; using System.Collections.Immutable; using System.IO; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index f624149163486..6158b43a130c8 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.ComponentModel.Design; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs index 8ecab4288f15e..79256bf75f754 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/UnusedReferenceExtensions.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System.Collections.Immutable; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.ProjectSystem.Api; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs index 11eb1be0f1b69..fd0d36fc74ffa 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/VisualStudioReferenceCleanupService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.Composition; From c818664ee88179e1ae7a5af3e3eb4597837f1f03 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 15 Dec 2020 15:25:26 -0800 Subject: [PATCH 10/57] Handle case where compilation is null --- .../Portable/UnusedReferences/UnusedReferencesService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index f4c21fe9cb822..a4326996f5d5f 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -33,7 +33,12 @@ public async Task> GetUnusedReferencesAsync( { // Create a lookup of used assembly paths var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken).Select(reference => reference.Display); + if (compilation is null) + { + return ImmutableArray.Empty; + } + + var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken).Select(reference => reference.Display).OfType(); var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); var unusedReferences = ImmutableArray.CreateBuilder(); From 10686183afb80fdb2a26b29a3d4e0b002770b4b3 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 15 Dec 2020 15:25:45 -0800 Subject: [PATCH 11/57] Add no unused references found popup --- .../UnusedReferences/RemoveUnusedReferencesCommandHandler.cs | 4 +++- src/VisualStudio/Core/Def/ServicesVSResources.resx | 3 +++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf | 5 +++++ src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf | 5 +++++ .../Core/Def/xlf/ServicesVSResources.zh-Hans.xlf | 5 +++++ .../Core/Def/xlf/ServicesVSResources.zh-Hant.xlf | 5 +++++ 15 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index 6158b43a130c8..e50fa806addd6 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -19,6 +19,7 @@ using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.Dialog; using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets; +using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Utilities; @@ -123,7 +124,7 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs if (TryGetSelectedProjectHierarchy(out var hierarchy)) { Project? project = null; - ImmutableArray referenceUpdates; + ImmutableArray referenceUpdates = default; _threadOperationExecutor.Execute(ServicesVSResources.Remove_Unused_References, ServicesVSResources.Analyzing_project_references, allowCancellation: true, showProgress: true, (operationContext) => { (project, referenceUpdates) = GetUnusedReferencesForProjectHierarchy(hierarchy, operationContext.UserCancellationToken); @@ -132,6 +133,7 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs if (project is null || referenceUpdates.IsEmpty) { + MessageDialog.Show(ServicesVSResources.Remove_Unused_References, "No unused references were found.", MessageDialogCommandSet.Ok); return; } diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 1ed7788ad0072..2b2f174742a43 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1635,4 +1635,7 @@ I agree to all of the foregoing: Updating project references. + + No unused references were found. + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 5a7fdee2e7a6d..53b7307d11996 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -602,6 +602,11 @@ Název nového typu: + + No unused references were found. + No unused references were found. + + Non-public methods Neveřejné metody diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index e0cf838c1c972..ae9e1a791cfc3 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -602,6 +602,11 @@ Neuer Typname: + + No unused references were found. + No unused references were found. + + Non-public methods Nicht öffentliche Methoden diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 92d7c1023e1d6..1e5abf7d04b4f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -602,6 +602,11 @@ Nombre de tipo nuevo: + + No unused references were found. + No unused references were found. + + Non-public methods Miembros no públicos diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 77495eddda64e..e05990d12bf9c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -602,6 +602,11 @@ Nouveau nom de type : + + No unused references were found. + No unused references were found. + + Non-public methods Méthodes non publiques diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index da734fb026765..bce5555211c8e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -602,6 +602,11 @@ Nuovo nome di tipo: + + No unused references were found. + No unused references were found. + + Non-public methods Metodi non pubblici diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index e583dd5029100..be84d6dcbb079 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -602,6 +602,11 @@ 新しい型名: + + No unused references were found. + No unused references were found. + + Non-public methods パブリックでないメソッド diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index dbcbd2b4cb2ef..79bbf6a323cad 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -602,6 +602,11 @@ 새 형식 이름: + + No unused references were found. + No unused references were found. + + Non-public methods public이 아닌 메서드 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 98bd555143291..1d7145e221f9e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -602,6 +602,11 @@ Nazwa nowego typu: + + No unused references were found. + No unused references were found. + + Non-public methods Metody niepubliczne diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 6f10a5d751841..bb037e21e4296 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -602,6 +602,11 @@ Novo Nome de Tipo: + + No unused references were found. + No unused references were found. + + Non-public methods Métodos não públicos diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index effbb1f75c6fc..2b13f2fb4eaf9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -602,6 +602,11 @@ Новое имя типа: + + No unused references were found. + No unused references were found. + + Non-public methods Методы, не являющиеся открытыми diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 0f4a84513b0b9..34792cebbc233 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -602,6 +602,11 @@ Yeni Tür Adı: + + No unused references were found. + No unused references were found. + + Non-public methods Ortak olmayan yöntemler diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index d024518308f5b..ef7cd0306bea4 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -602,6 +602,11 @@ 新类型名称: + + No unused references were found. + No unused references were found. + + Non-public methods 非公共成员 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 97ebcb59b9c50..bbcd6b4e5a083 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -602,6 +602,11 @@ 新的型別名稱: + + No unused references were found. + No unused references were found. + + Non-public methods 非公用方法 From 6a1c0fb4f5aed222faef85d41d7d9363ba80dff1 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 15 Dec 2020 17:33:42 -0800 Subject: [PATCH 12/57] Add comfirmation dialog when there are reference changes --- .../RemoveUnusedReferencesCommandHandler.cs | 36 +++++++++++++++---- .../Core/Def/ServicesVSResources.resx | 3 ++ .../Core/Def/xlf/ServicesVSResources.cs.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.de.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.es.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.fr.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.it.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.ja.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.ko.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.pl.xlf | 5 +++ .../Def/xlf/ServicesVSResources.pt-BR.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.ru.xlf | 5 +++ .../Core/Def/xlf/ServicesVSResources.tr.xlf | 5 +++ .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 5 +++ .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 5 +++ 15 files changed, 98 insertions(+), 6 deletions(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index e50fa806addd6..3e5ebfc4b84bd 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -133,7 +133,7 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs if (project is null || referenceUpdates.IsEmpty) { - MessageDialog.Show(ServicesVSResources.Remove_Unused_References, "No unused references were found.", MessageDialogCommandSet.Ok); + MessageDialog.Show(ServicesVSResources.Remove_Unused_References, ServicesVSResources.No_unused_references_were_found, MessageDialogCommandSet.Ok); return; } @@ -143,9 +143,28 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs return; } + // If we are removing, then that is a change or if we are newly marking a reference as TreatAsUsed, + // then that is a change. + var referenceChanges = referenceUpdates + .Where(update => update.Action != UpdateAction.TreatAsUsed || !update.ReferenceInfo.TreatAsUsed) + .ToImmutableArray(); + + // If there are no changes, then we can return + if (referenceChanges.IsEmpty) + { + return; + } + + // Since undo/redo is not supported, get confirmation that we should apply these changes. + var result = MessageDialog.Show(ServicesVSResources.Remove_Unused_References, ServicesVSResources.This_action_cannot_be_undone_Do_you_wish_to_continue, MessageDialogCommandSet.YesNo); + if (result == MessageDialogCommand.No) + { + return; + } + _threadOperationExecutor.Execute(ServicesVSResources.Remove_Unused_References, ServicesVSResources.Updating_project_references, allowCancellation: false, showProgress: true, (operationContext) => { - ApplyUnusedReferenceUpdates(project, referenceUpdates, CancellationToken.None); + ApplyUnusedReferenceUpdates(project, referenceChanges, CancellationToken.None); }); } @@ -178,7 +197,7 @@ private ImmutableArray GetUnusedReferencesForProject(Project pr { ImmutableArray unusedReferences = ThreadHelper.JoinableTaskFactory.Run(async () => { - var projectReferences = await _referenceCleanupService.GetProjectReferencesAsync(project.FilePath, cancellationToken).ConfigureAwait(true); + var projectReferences = await _referenceCleanupService.GetProjectReferencesAsync(project.FilePath!, cancellationToken).ConfigureAwait(true); var references = ProjectAssetsReader.ReadReferences(projectReferences, projectAssetsFile, targetFrameworkMoniker); return await _unusedReferencesService.GetUnusedReferencesAsync(project, references, targetFrameworkMoniker, cancellationToken).ConfigureAwait(true); @@ -193,11 +212,16 @@ private ImmutableArray GetUnusedReferencesForProject(Project pr private Window GetUnusedReferencesDialog(Project project, ImmutableArray referenceUpdates) { - var uiShell = _serviceProvider.GetService(); - uiShell.GetDialogOwnerHwnd(out var ownerHwnd); - var dialog = _unusedReferenceDialogProvider.CreateDialog(project, referenceUpdates); + var uiShell = _serviceProvider?.GetService(); + if (uiShell is null) + { + return dialog; + } + + uiShell.GetDialogOwnerHwnd(out var ownerHwnd); + var windowHelper = new WindowInteropHelper(dialog) { Owner = ownerHwnd diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 2b2f174742a43..1c6ba4b29b77f 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1638,4 +1638,7 @@ I agree to all of the foregoing: No unused references were found. + + This action cannot be undone. Do you wish to continue? + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 53b7307d11996..a12c5312974b8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -922,6 +922,11 @@ Generátor {0}, který vygeneroval tento soubor, přestal tento soubor generovat. Soubor už není součástí projektu. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Tento soubor se automaticky vygeneroval pomocí generátoru {0} a nedá se upravit. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index ae9e1a791cfc3..8b821ca495776 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -922,6 +922,11 @@ Der Generator "{0}" hat diese Datei nicht vollständig generiert. Diese Datei wird nicht mehr in Ihr Projekt einbezogen. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Diese Datei wird automatisch vom Generator "{0}" generiert und kann nicht bearbeitet werden. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 1e5abf7d04b4f..6b839b584ccc2 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -922,6 +922,11 @@ El generador "{0}" que creaba este archivo ha dejado de generarlo; el archivo ya no se incluye en el proyecto. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. El generador "{0}" crea este archivo de forma automática y no se puede editar. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index e05990d12bf9c..11d9c3cce7a85 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -922,6 +922,11 @@ Le générateur '{0}' qui a généré ce fichier a arrêté de générer ce dernier. Le fichier n'est plus inclus dans votre projet. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Ce fichier est généré automatiquement par le générateur '{0}' et ne peut pas être modifié. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index bce5555211c8e..a19c34cb6f6a7 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -922,6 +922,11 @@ Il generatore '{0}' che ha generato questo file non genera più il file. Questo file non è più incluso nel progetto. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Questo file è stato generato automaticamente dal generatore '{0}' e non è modificabile. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index be84d6dcbb079..2c8d97d70bf56 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -922,6 +922,11 @@ このファイルの生成元であるジェネレーター '{0}' で、このファイルの生成が停止しました。このファイルはもうプロジェクトに含まれていません。 + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. このファイルはジェネレーター '{0}' によって自動生成されているため、編集できません。 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 79bbf6a323cad..698199900de01 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -922,6 +922,11 @@ 이 파일을 생성한 생성기 '{0}'이(가) 이 파일 생성을 중지했습니다. 이 파일은 프로젝트에 더 이상 포함되지 않습니다. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. 이 파일은 생성기 '{0}'(으)로 자동 생성되며 편집할 수 없습니다. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 1d7145e221f9e..616de92d97967 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -922,6 +922,11 @@ Generator „{0}”, który wygenerował ten plik, przestał generować ten plik; ten plik nie jest już uwzględniany w Twoim projekcie. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Ten plik jest generowany automatycznie przez generator „{0}” i nie może być edytowany. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index bb037e21e4296..aae54eceb2d35 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -922,6 +922,11 @@ O gerador '{0}' que gerou esse arquivo parou de gerá-lo. Esse arquivo não será mais incluído no projeto. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Esse arquivo é gerado automaticamente pelo gerador '{0}' e não pode ser editado. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 2b13f2fb4eaf9..09a2e64cd7436 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -922,6 +922,11 @@ Генератор "{0}", создавший этот файл, остановил создание этого файла; этот файл больше не включен в проект. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Этот файл создан автоматически генератором "{0}" и не может быть изменен. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 34792cebbc233..7cf69351ce9d7 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -922,6 +922,11 @@ Bu dosyayı oluşturan '{0}' oluşturucusu bu dosyayı oluşturmayı durdurdu; bu dosya artık projenize dahil edilmiyor. + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. Bu dosya, '{0}' oluşturucusu tarafından otomatik olarak oluşturuldu ve düzenlenemez. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index ef7cd0306bea4..ffc3e2ca8579a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -922,6 +922,11 @@ 生成此文件的生成器“{0}”已停止生成此文件;项目中不再包含此文件。 + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. 此文件由生成器“{0}”自动生成,无法编辑。 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index bbcd6b4e5a083..cc15ddaacb840 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -922,6 +922,11 @@ 產生此檔案的產生器 '{0}' 已停止產生此檔案; 此檔案已不再包含在您的專案中。 + + This action cannot be undone. Do you wish to continue? + This action cannot be undone. Do you wish to continue? + + This file is auto-generated by the generator '{0}' and cannot be edited. 此檔案是由產生器 '{0}' 自動產生,無法加以編輯。 From cfac8035047d6f4c4dc453283cb627f7d4c0485a Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 16 Dec 2020 22:05:14 -0800 Subject: [PATCH 13/57] Add option to show Remove Unused Reference command --- .../Shared/Options/FeatureOnOffOptions.cs | 8 ++- .../Options/AdvancedOptionPageControl.xaml | 3 + .../Options/AdvancedOptionPageControl.xaml.cs | 1 + .../Impl/Options/AdvancedOptionPageStrings.cs | 3 + .../RemoveUnusedReferencesCommandHandler.cs | 15 ++--- .../Core/Def/ServicesVSResources.resx | 57 ++++++++++--------- .../Core/Def/xlf/ServicesVSResources.cs.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.de.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.es.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.fr.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.it.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.ja.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.ko.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.pl.xlf | 5 ++ .../Def/xlf/ServicesVSResources.pt-BR.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.ru.xlf | 5 ++ .../Core/Def/xlf/ServicesVSResources.tr.xlf | 5 ++ .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 5 ++ .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 5 ++ .../Options/AdvancedOptionPageControl.xaml | 2 + .../Options/AdvancedOptionPageControl.xaml.vb | 1 + .../Impl/Options/AdvancedOptionPageStrings.vb | 3 + 22 files changed, 120 insertions(+), 38 deletions(-) diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index 82db496d92a15..ee0875e847dcb 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -86,6 +86,11 @@ internal static class FeatureOnOffOptions public static readonly PerLanguageOption2 AddImportsOnPaste = new( nameof(FeatureOnOffOptions), nameof(AddImportsOnPaste), defaultValue: false); + + public static readonly Option2 OfferRemoveUnusedReferences = new( + nameof(FeatureOnOffOptions), nameof(OfferRemoveUnusedReferences), defaultValue: false, + storageLocations: new RoamingProfileStorageLocation($"TextEditor.{nameof(OfferRemoveUnusedReferences)}")); + } [ExportOptionProvider, Shared] @@ -116,6 +121,7 @@ public FeatureOnOffOptionsProvider() FeatureOnOffOptions.StreamingGoToImplementation, FeatureOnOffOptions.NavigateToDecompiledSources, FeatureOnOffOptions.UseEnhancedColors, - FeatureOnOffOptions.AddImportsOnPaste); + FeatureOnOffOptions.AddImportsOnPaste, + FeatureOnOffOptions.OfferRemoveUnusedReferences); } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index a5584495dfdb9..286c66cde3e2e 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -42,6 +42,9 @@ + + SchemeName.VisualStudio2017; + + public static string Option_Show_Remove_Unused_References_command_in_Solution_Explorer_experimental + => ServicesVSResources.Show_Remove_Unused_References_command_in_Solution_Explorer_experimental; } } diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index 3e5ebfc4b84bd..a216c93199ba0 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -14,6 +14,7 @@ using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -63,7 +64,7 @@ public void Initialize(IServiceProvider serviceProvider) Contract.ThrowIfNull(_serviceProvider); - // Hook up the "Run Code Analysis" menu command for CPS based managed projects. + // Hook up the "Remove Unused References" menu command for CPS based managed projects. var menuCommandService = (IMenuCommandService)_serviceProvider.GetService(typeof(IMenuCommandService)); if (menuCommandService != null) { @@ -91,21 +92,15 @@ private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, Eve { var command = (OleMenuCommand)sender; - // We hook up the "Run Code Analysis" menu commands for CPS based managed projects. - // These commands are already hooked up for csproj based projects in StanCore, but those will eventually go away. + // Only show the "Remove Unused Reference" menu commands for CPS based managed projects. var visible = TryGetSelectedProjectHierarchy(out var hierarchy) && hierarchy.IsCapabilityMatch("CPS") && - hierarchy.IsCapabilityMatch(".NET"); + hierarchy.IsCapabilityMatch(".NET") && + _workspace.Options.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferences); var enabled = false; if (visible) { - if (hierarchy!.TryGetProject(out _)) - { - // Change to show the name of the project as part of the menu item display text. - // command.Text = string.Format("Remove Unused References for {0}", project!.Name); - } - enabled = !IsBuildActive(); } diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 1c6ba4b29b77f..d7f131c91e63c 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1,17 +1,17 @@ - @@ -1638,6 +1638,9 @@ I agree to all of the foregoing: No unused references were found. + + Show "Remove Unused References" command in Solution Explorer (experimental) + This action cannot be undone. Do you wish to continue? diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index a12c5312974b8..9ed30b8a05597 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -867,6 +867,11 @@ Vybrat členy: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Zobrazit seznam pro doplňování diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 8b821ca495776..6c851051537c2 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -867,6 +867,11 @@ Member auswählen: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Vervollständigungsliste anzeigen diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 6b839b584ccc2..4307ac8aa0e55 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -867,6 +867,11 @@ Seleccionar miembros: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Mostrar lista de finalización diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 11d9c3cce7a85..d8c591aeca2c3 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -867,6 +867,11 @@ Sélectionner les membres : + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Afficher la liste de saisie semi-automatique diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index a19c34cb6f6a7..08716ae9ceba2 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -867,6 +867,11 @@ Selezionare i membri: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Mostra l'elenco di completamento diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 2c8d97d70bf56..59bc989efa9b6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -867,6 +867,11 @@ メンバーの選択: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list 入力候補一覧の表示 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 698199900de01..2ae22f8eaad78 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -867,6 +867,11 @@ 멤버 선택: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list 완성 목록 표시 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 616de92d97967..d82d6a5d858e8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -867,6 +867,11 @@ Wybierz składowe: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Pokaż listę uzupełniania diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index aae54eceb2d35..bc849decf16a6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -867,6 +867,11 @@ Selecionar membros: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Mostrar a lista de conclusão diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 09a2e64cd7436..c9ddde5ffc32f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -867,6 +867,11 @@ Выбрать элементы: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Показать список завершения diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 7cf69351ce9d7..96a5d6dbf83e6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -867,6 +867,11 @@ Üye seçin: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list Tamamlama listesini göster diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index ffc3e2ca8579a..199c9dceeb7dc 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -867,6 +867,11 @@ 选择成员: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list 显示完成列表 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index cc15ddaacb840..08d5f342e9750 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -867,6 +867,11 @@ 選取成員: + + Show "Remove Unused References" command in Solution Explorer (experimental) + Show "Remove Unused References" command in Solution Explorer (experimental) + + Show completion list 顯示自動完成清單 diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml index 8325cf3521030..368b73ff6cc85 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml @@ -30,6 +30,8 @@ + Date: Wed, 16 Dec 2020 22:05:59 -0800 Subject: [PATCH 14/57] Add ellipses to command text --- src/VisualStudio/Core/Def/Commands.vsct | 2 +- src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf | 4 ++-- src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/VisualStudio/Core/Def/Commands.vsct b/src/VisualStudio/Core/Def/Commands.vsct index 7f9dde6165600..c9dd185551fc5 100644 --- a/src/VisualStudio/Core/Def/Commands.vsct +++ b/src/VisualStudio/Core/Def/Commands.vsct @@ -414,7 +414,7 @@ DefaultInvisible DefaultDisabled - Remove &Unused References + Remove &Unused References... RemoveUnusedReferences RemoveUnusedReferences RemoveUnusedReferences diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf index c801ac1d10632..6ab46a153fc53 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.cs.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf index 23eff5dbf00f4..39691247a87d9 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.de.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf index 3ce74cad111b2..63941e8dbc88d 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.es.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf index af010ccfe550c..5eaa9a71bec58 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.fr.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf index 3ae170a22779a..bccc689169acb 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.it.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf index caf5f517e7d24..2ce24c0fc615d 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ja.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf index aed9a73b5036b..fed9ec757ba77 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ko.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf index 6feb5eba39b32..bb907800c0146 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pl.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf index 64b93066817b8..5b6cd2c43c66c 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.pt-BR.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf index efaefa96935d1..d68b6204e131e 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.ru.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf index 4c8a4a9ad847f..1d0204a6df606 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.tr.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf index 41227b0ad15c7..10253dc60ebad 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hans.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... diff --git a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf index bcfe9f13a228d..70ff22c6243ae 100644 --- a/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/Commands.vsct.zh-Hant.xlf @@ -213,8 +213,8 @@ - Remove &Unused References - Remove &Unused References + Remove &Unused References... + Remove &Unused References... From 491c32e48027a1fa3578aa966086f8d1381868d5 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 16 Dec 2020 22:20:19 -0800 Subject: [PATCH 15/57] Remove TFM argument from UpdateReferencesAsync --- .../IUnusedReferencesService.cs | 1 - .../UnusedReferencesService.cs | 36 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs index 6cbfdb1e1cc32..7dd90e0c2186a 100644 --- a/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/IUnusedReferencesService.cs @@ -17,7 +17,6 @@ internal interface IUnusedReferencesService : IWorkspaceService Task> GetUnusedReferencesAsync( Project project, ImmutableArray references, - string targetFrameworkMoniker, CancellationToken cancellationToken); /// diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index a4326996f5d5f..8c6a6527000e7 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -16,7 +16,12 @@ namespace Microsoft.CodeAnalysis.UnusedReferences [ExportWorkspaceService(typeof(IUnusedReferencesService), ServiceLayer.Default), Shared] internal class UnusedReferencesService : IUnusedReferencesService { - private readonly ReferenceType[] _processingOrder = new[] { ReferenceType.Project, ReferenceType.Package, ReferenceType.Assembly }; + private readonly ReferenceType[] _processingOrder = new[] + { + ReferenceType.Project, + ReferenceType.Package, + ReferenceType.Assembly + }; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -28,7 +33,6 @@ public UnusedReferencesService() public async Task> GetUnusedReferencesAsync( Project project, ImmutableArray references, - string targetFrameworkMoniker, CancellationToken cancellationToken) { // Create a lookup of used assembly paths @@ -38,12 +42,17 @@ public async Task> GetUnusedReferencesAsync( return ImmutableArray.Empty; } - var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken).Select(reference => reference.Display).OfType(); + var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken) + .Select(reference => reference.Display) + .OfType(); var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); var unusedReferences = ImmutableArray.CreateBuilder(); - var referencesByType = references.GroupBy(reference => reference.ReferenceType).ToImmutableDictionary(group => group.Key); + var referencesByType = references.GroupBy(reference => reference.ReferenceType) + .ToImmutableDictionary(group => group.Key); + // We process the references in order by their type. This means we favor transitive references + // over direct references where possible. foreach (var referenceType in _processingOrder) { if (!referencesByType.ContainsKey(referenceType)) @@ -63,10 +72,10 @@ private static IEnumerable DetermineUnusedReferences(IEnumerable - reference.CompilationAssemblies.Any(assembly => usedAssemblyLookup.Contains(assembly))); + reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)); var toplevelUsedAssemblyReferences = toplevelUsedReferences.SelectMany(reference => reference.GetAllCompilationAssemblies()); - // Remove all assemblies that are brought into the compilation from the toplevel used references. When + // Remove all assemblies that are brought into the compilation from those toplevel used references. When // determining transtively used references this will reduce false positives. var remainingReferences = references.Except(toplevelUsedReferences); var remainingUsedAssemblyReferences = usedAssemblyReferences.Except(toplevelUsedAssemblyReferences); @@ -78,14 +87,15 @@ private static IEnumerable DetermineUnusedReferences(IEnumerable remainingUsedAssemblyLookup.Contains(assembly))) + if (!allCompilationAssemblies.Any(remainingUsedAssemblyLookup.Contains)) { - // References that do not contribute a used compilation assembly are considered unsused. + // None of the assemblies brought into this compilation are in the remaining + // used assemblies list, so we will consider the reference unused. unusedReferences.Add(reference); continue; } @@ -101,8 +111,6 @@ public async Task UpdateReferencesAsync(Project project, ImmutableArray { var referenceCleanupService = project.Solution.Workspace.Services.GetRequiredService(); - // Remove unused usings - foreach (var referenceUpdate in referenceUpdates) { if (referenceUpdate.Action == UpdateAction.None) @@ -124,9 +132,9 @@ public async Task UpdateReferencesAsync(Project project, ImmutableArray } await referenceCleanupService.TryUpdateReferenceAsync( - project.FilePath, + project.FilePath!, referenceUpdate, - cancellationToken).ConfigureAwait(true); + cancellationToken).ConfigureAwait(false); } return project; From ca8179aa6cca44b9fe6f5509d09cca0b775f7e42 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Thu, 17 Dec 2020 13:35:33 -0800 Subject: [PATCH 16/57] Fix build error --- .../UnusedReferences/RemoveUnusedReferencesCommandHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index a216c93199ba0..6c8edfb6d0017 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -195,7 +195,7 @@ private ImmutableArray GetUnusedReferencesForProject(Project pr var projectReferences = await _referenceCleanupService.GetProjectReferencesAsync(project.FilePath!, cancellationToken).ConfigureAwait(true); var references = ProjectAssetsReader.ReadReferences(projectReferences, projectAssetsFile, targetFrameworkMoniker); - return await _unusedReferencesService.GetUnusedReferencesAsync(project, references, targetFrameworkMoniker, cancellationToken).ConfigureAwait(true); + return await _unusedReferencesService.GetUnusedReferencesAsync(project, references, cancellationToken).ConfigureAwait(true); }); var referenceUpdates = unusedReferences From 6e69823f713965f46d412f96481ca2c1097e4b9f Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Thu, 17 Dec 2020 17:26:44 -0800 Subject: [PATCH 17/57] Add tests for the UnusedReferencesService --- src/Compilers/Test/Core/Traits/Traits.cs | 1 + .../UnusedReferencesServiceTests.cs | 185 ++++++++++++++++++ .../UnusedReferencesService.cs | 67 +++++-- 3 files changed, 232 insertions(+), 21 deletions(-) create mode 100644 src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index e3dab710c0bab..996e0eff50a55 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -292,6 +292,7 @@ public static class Features public const string ToggleBlockComment = nameof(ToggleBlockComment); public const string ToggleLineComment = nameof(ToggleLineComment); public const string TypeInferenceService = nameof(TypeInferenceService); + public const string UnusedReferences = nameof(UnusedReferences); public const string ValidateFormatString = nameof(ValidateFormatString); public const string ValidateRegexString = nameof(ValidateRegexString); public const string Venus = nameof(Venus); diff --git a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs new file mode 100644 index 0000000000000..8fd8771503607 --- /dev/null +++ b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs @@ -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 UnusedReferencesServiceTests + { + 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.Equal(1, unusedReferences.Length); + } + + [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_ReferencesBroughtInTranstivelyAndDirectly_AreReturned() + { + var usedAssemblies = new[] { UsedAssemblyPath }; + var transitivelyUsedReference = ProjectReference(UnusedAssemblyPath, PackageReference(UsedAssemblyPath)); + var unneededReference = PackageReference(UsedAssemblyPath); + + var unusedReferences = GetUnusedReferences(usedAssemblies, transitivelyUsedReference, unneededReference); + + Assert.Contains(unneededReference, unusedReferences); + Assert.Equal(1, unusedReferences.Length); + } + + [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.Empty, + dependencies: ImmutableArray.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.Equal(1, appliedUpdates.Length); + } + + [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.Equal(1, appliedUpdates.Length); + } + + private static ImmutableArray GetUnusedReferences(string[] usedCompilationAssemblies, params ReferenceInfo[] references) + => UnusedReferencesService.GetUnusedReferences(usedCompilationAssemblies, references.ToImmutableArray()); + + private static async Task> ApplyReferenceUpdatesAsync(params ReferenceUpdate[] referenceUpdates) + { + var referenceCleanupService = new TestReferenceCleanupService(); + + await UnusedReferencesService.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.Empty); + + private class TestReferenceCleanupService : IReferenceCleanupService + { + private readonly List _appliedUpdates = new(); + public IReadOnlyList AppliedUpdates => _appliedUpdates; + + public Task> GetProjectReferencesAsync(string projectPath, CancellationToken cancellationToken) + { + throw new System.NotImplementedException(); + } + + public Task TryUpdateReferenceAsync(string projectPath, ReferenceUpdate referenceUpdate, CancellationToken cancellationToken) + { + _appliedUpdates.Add(referenceUpdate); + return Task.FromResult(true); + } + } + } +} diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 8c6a6527000e7..8601941bbe36b 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.UnusedReferences [ExportWorkspaceService(typeof(IUnusedReferencesService), ServiceLayer.Default), Shared] internal class UnusedReferencesService : IUnusedReferencesService { - private readonly ReferenceType[] _processingOrder = new[] + private static readonly ReferenceType[] _processingOrder = new[] { ReferenceType.Project, ReferenceType.Package, @@ -42,10 +42,18 @@ public async Task> GetUnusedReferencesAsync( return ImmutableArray.Empty; } - var usedAssemblyReferences = compilation.GetUsedAssemblyReferences(cancellationToken) + var usedCompilationAssemblies = compilation.GetUsedAssemblyReferences(cancellationToken) .Select(reference => reference.Display) .OfType(); - var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); + + return GetUnusedReferences(usedCompilationAssemblies, references); + } + + internal static ImmutableArray GetUnusedReferences( + IEnumerable usedCompilationAssemblies, + ImmutableArray references) + { + var usedAssemblyLookup = usedCompilationAssemblies.ToImmutableHashSet(); var unusedReferences = ImmutableArray.CreateBuilder(); var referencesByType = references.GroupBy(reference => reference.ReferenceType) @@ -60,15 +68,21 @@ public async Task> GetUnusedReferencesAsync( continue; } - usedAssemblyReferences = DetermineUnusedReferences(referencesByType[referenceType], usedAssemblyReferences, unusedReferences); + usedCompilationAssemblies = DetermineUnusedReferences( + referencesByType[referenceType], + usedCompilationAssemblies, + unusedReferences); } return unusedReferences.ToImmutableArray(); } - private static IEnumerable DetermineUnusedReferences(IEnumerable references, IEnumerable usedAssemblyReferences, ImmutableArray.Builder unusedReferences) + private static IEnumerable DetermineUnusedReferences( + IEnumerable references, + IEnumerable usedCompilationAssemblies, + ImmutableArray.Builder unusedReferences) { - var usedAssemblyLookup = usedAssemblyReferences.ToImmutableHashSet(); + var usedAssemblyLookup = usedCompilationAssemblies.ToImmutableHashSet(); // Determine which toplevel references have compilation assemblies in set of used assemblies. var toplevelUsedReferences = references.Where(reference => @@ -78,7 +92,7 @@ private static IEnumerable DetermineUnusedReferences(IEnumerable DetermineUnusedReferences(IEnumerable UpdateReferencesAsync(Project project, ImmutableArray referenceUpdates, CancellationToken cancellationToken) + public async Task UpdateReferencesAsync( + Project project, + ImmutableArray referenceUpdates, + CancellationToken cancellationToken) { var referenceCleanupService = project.Solution.Workspace.Services.GetRequiredService(); + await ApplyReferenceUpdatesAsync(referenceCleanupService, project.FilePath!, referenceUpdates, cancellationToken).ConfigureAwait(false); + + return project.Solution.Workspace.CurrentSolution.GetProject(project.Id)!; + } + + internal static async Task ApplyReferenceUpdatesAsync( + IReferenceCleanupService referenceCleanupService, + string projectFilePath, + ImmutableArray referenceUpdates, + CancellationToken cancellationToken) + { foreach (var referenceUpdate in referenceUpdates) { - if (referenceUpdate.Action == UpdateAction.None) + // If the update action would not change the reference, then + // continue to the next update. + if (referenceUpdate.Action == UpdateAction.TreatAsUnused && + !referenceUpdate.ReferenceInfo.TreatAsUsed) { - referenceUpdate.Action = referenceUpdate.ReferenceInfo.TreatAsUsed - ? UpdateAction.TreatAsUnused - : UpdateAction.None; + continue; } - else if (referenceUpdate.Action == UpdateAction.TreatAsUsed) + else if (referenceUpdate.Action == UpdateAction.TreatAsUsed && + referenceUpdate.ReferenceInfo.TreatAsUsed) { - referenceUpdate.Action = referenceUpdate.ReferenceInfo.TreatAsUsed - ? UpdateAction.None - : UpdateAction.TreatAsUsed; + continue; } - - if (referenceUpdate.Action == UpdateAction.None) + else if (referenceUpdate.Action == UpdateAction.None) { continue; } await referenceCleanupService.TryUpdateReferenceAsync( - project.FilePath!, + projectFilePath, referenceUpdate, cancellationToken).ConfigureAwait(false); } - - return project; } } } From 18f2655fbf4f12db5e36d48078788fe7a45456d9 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:11:40 -0800 Subject: [PATCH 18/57] Remove use of IEnumerable from UnusedReferencesService --- .../UnusedReferencesServiceTests.cs | 2 +- .../UnusedReferencesService.cs | 33 ++++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs index 8fd8771503607..86c5e3819b5f1 100644 --- a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs +++ b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs @@ -123,7 +123,7 @@ public async Task ApplyReferenceUpdates_MixOfChangeAndNoChangeUpdates_ChangesAre } private static ImmutableArray GetUnusedReferences(string[] usedCompilationAssemblies, params ReferenceInfo[] references) - => UnusedReferencesService.GetUnusedReferences(usedCompilationAssemblies, references.ToImmutableArray()); + => UnusedReferencesService.GetUnusedReferences(usedCompilationAssemblies.ToImmutableHashSet(), references.ToImmutableArray()); private static async Task> ApplyReferenceUpdatesAsync(params ReferenceUpdate[] referenceUpdates) { diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 8601941bbe36b..0e0326936374d 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -42,19 +42,18 @@ public async Task> GetUnusedReferencesAsync( return ImmutableArray.Empty; } - var usedCompilationAssemblies = compilation.GetUsedAssemblyReferences(cancellationToken) + var usedAssemblyLookup = compilation.GetUsedAssemblyReferences(cancellationToken) .Select(reference => reference.Display) - .OfType(); + .OfType() + .ToImmutableHashSet(); - return GetUnusedReferences(usedCompilationAssemblies, references); + return GetUnusedReferences(usedAssemblyLookup, references); } internal static ImmutableArray GetUnusedReferences( - IEnumerable usedCompilationAssemblies, + ImmutableHashSet usedAssemblyLookup, ImmutableArray references) { - var usedAssemblyLookup = usedCompilationAssemblies.ToImmutableHashSet(); - var unusedReferences = ImmutableArray.CreateBuilder(); var referencesByType = references.GroupBy(reference => reference.ReferenceType) .ToImmutableDictionary(group => group.Key); @@ -68,22 +67,20 @@ internal static ImmutableArray GetUnusedReferences( continue; } - usedCompilationAssemblies = DetermineUnusedReferences( - referencesByType[referenceType], - usedCompilationAssemblies, + usedAssemblyLookup = DetermineUnusedReferences( + referencesByType[referenceType].ToImmutableArray(), + usedAssemblyLookup, unusedReferences); } return unusedReferences.ToImmutableArray(); } - private static IEnumerable DetermineUnusedReferences( - IEnumerable references, - IEnumerable usedCompilationAssemblies, + private static ImmutableHashSet DetermineUnusedReferences( + ImmutableArray references, + ImmutableHashSet usedAssemblyLookup, ImmutableArray.Builder unusedReferences) { - var usedAssemblyLookup = usedCompilationAssemblies.ToImmutableHashSet(); - // Determine which toplevel references have compilation assemblies in set of used assemblies. var toplevelUsedReferences = references.Where(reference => reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)); @@ -92,8 +89,7 @@ private static IEnumerable DetermineUnusedReferences( // Remove all assemblies that are brought into the compilation from those toplevel used references. When // determining transtively used references this will reduce false positives. var remainingReferences = references.Except(toplevelUsedReferences); - var remainingUsedAssemblyReferences = usedCompilationAssemblies.Except(toplevelUsedAssemblyReferences); - var remainingUsedAssemblyLookup = remainingUsedAssemblyReferences.ToImmutableHashSet(); + var remainingUsedAssemblyLookup = usedAssemblyLookup.Except(toplevelUsedAssemblyReferences); // Determine which transtive references have compilation assemblies in the set of remaining used assemblies. foreach (var reference in remainingReferences) @@ -114,11 +110,10 @@ private static IEnumerable DetermineUnusedReferences( continue; } - remainingUsedAssemblyReferences = remainingUsedAssemblyReferences.Except(allCompilationAssemblies); - remainingUsedAssemblyLookup = remainingUsedAssemblyReferences.ToImmutableHashSet(); + remainingUsedAssemblyLookup = remainingUsedAssemblyLookup.Except(allCompilationAssemblies); } - return remainingUsedAssemblyReferences; + return remainingUsedAssemblyLookup; } public async Task UpdateReferencesAsync( From 0d15843d510c41adaa347735cb3f18db36b62c00 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:16:32 -0800 Subject: [PATCH 19/57] Update ProjectAssetsReader comment with a tracking issue --- .../UnusedReferences/ProjectAssets/ProjectAssetsReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs index 17e3ffa21003a..b60a7677899c6 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs @@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets { // This class will read the dependency heirarchy from the project.assets.json file. The format of this file - // is subject to change and in the future this information will be provided by an API with the ProjectSystem. + // is subject to change and in the future this information will be provided by an API. See https://github.com/dotnet/roslyn/issues/50054 internal static class ProjectAssetsReader { public static ImmutableArray ReadReferences( From eb4d85fa6431091d12aa28cc857eece7f58fac06 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:20:53 -0800 Subject: [PATCH 20/57] Add comment about ignoring empty files in ProjectAssetsReader --- .../UnusedReferences/ProjectAssets/ProjectAssetsReader.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs index b60a7677899c6..336252ece9c75 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/ProjectAssets/ProjectAssetsReader.cs @@ -15,6 +15,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReference // is subject to change and in the future this information will be provided by an API. See https://github.com/dotnet/roslyn/issues/50054 internal static class ProjectAssetsReader { + // NuGet will include entries to keep empty folders from being removed. These entries can be ignored. + private const string NuGetEmptyFileName = "_._"; + public static ImmutableArray ReadReferences( ImmutableArray projectReferences, string projectAssetsFilePath, @@ -113,7 +116,7 @@ public static ImmutableArray ReadReferences( var packagesPath = projectAssets.Project?.Restore?.PackagesPath ?? string.Empty; var compilationAssemblies = targetLibrary.Compile != null ? targetLibrary.Compile.Keys - .Where(assemblyPath => !assemblyPath.EndsWith("_._")) + .Where(assemblyPath => !assemblyPath.EndsWith(NuGetEmptyFileName)) .Select(assemblyPath => Path.GetFullPath(Path.Combine(packagesPath, library.Path, assemblyPath))) .ToImmutableArray() : ImmutableArray.Empty; From a3e0f8303069a16488967d7e0913c05aecbcb14d Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:44:21 -0800 Subject: [PATCH 21/57] Remove memoization of compilation assemblies from ReferenceInfo --- .../Core/Portable/UnusedReferences/ReferenceInfo.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index 1f660ed02cb66..a558eb0fb2fbf 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -10,8 +10,6 @@ namespace Microsoft.CodeAnalysis.UnusedReferences { internal class ReferenceInfo { - private ImmutableArray? _allCompilationAssemblies; - /// /// Indicates the type of reference. /// @@ -55,11 +53,9 @@ public ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool /// public ImmutableArray GetAllCompilationAssemblies() { - _allCompilationAssemblies ??= CompilationAssemblies + return CompilationAssemblies .Concat(GetTransitiveCompilationAssemblies()) .ToImmutableArray(); - - return _allCompilationAssemblies.Value; } private IEnumerable GetTransitiveCompilationAssemblies() From 2f0c6f72540b3ccac966b0566582650c59197b3d Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:45:28 -0800 Subject: [PATCH 22/57] Remove empty line from UnusedReferencesService Co-authored-by: Andrew Hall --- .../Core/Portable/UnusedReferences/UnusedReferencesService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 0e0326936374d..790d5c7996d2d 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -27,7 +27,6 @@ internal class UnusedReferencesService : IUnusedReferencesService [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public UnusedReferencesService() { - } public async Task> GetUnusedReferencesAsync( From 5e81897b93dccdce961cc32ee05124b14c52225f Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:51:29 -0800 Subject: [PATCH 23/57] Use GetRequiredProject extension method --- .../Portable/UnusedReferences/UnusedReferencesService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 790d5c7996d2d..8827192766fbf 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,15 +1,15 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.UnusedReferences { @@ -124,7 +124,7 @@ public async Task UpdateReferencesAsync( await ApplyReferenceUpdatesAsync(referenceCleanupService, project.FilePath!, referenceUpdates, cancellationToken).ConfigureAwait(false); - return project.Solution.Workspace.CurrentSolution.GetProject(project.Id)!; + return project.Solution.Workspace.CurrentSolution.GetRequiredProject(project.Id); } internal static async Task ApplyReferenceUpdatesAsync( From 2e2efdf4500865612fc55942f72c9632024ed276 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 12:53:35 -0800 Subject: [PATCH 24/57] Update method name for clarity --- .../UnusedReferences/UnusedReferencesService.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 8827192766fbf..fee65d1cd97e8 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -57,6 +57,8 @@ internal static ImmutableArray GetUnusedReferences( var referencesByType = references.GroupBy(reference => reference.ReferenceType) .ToImmutableDictionary(group => group.Key); + var remainingUsedAssemblyLookup = usedAssemblyLookup; + // We process the references in order by their type. This means we favor transitive references // over direct references where possible. foreach (var referenceType in _processingOrder) @@ -66,16 +68,16 @@ internal static ImmutableArray GetUnusedReferences( continue; } - usedAssemblyLookup = DetermineUnusedReferences( + remainingUsedAssemblyLookup = AddUnusedReferences( referencesByType[referenceType].ToImmutableArray(), - usedAssemblyLookup, + remainingUsedAssemblyLookup, unusedReferences); } return unusedReferences.ToImmutableArray(); } - private static ImmutableHashSet DetermineUnusedReferences( + private static ImmutableHashSet AddUnusedReferences( ImmutableArray references, ImmutableHashSet usedAssemblyLookup, ImmutableArray.Builder unusedReferences) From 76a4792071749f13a92e51b70267721aa9e489b4 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 13:50:18 -0800 Subject: [PATCH 25/57] Move GetAllCompilationAssemblies out of ReferenceInfo --- .../Portable/UnusedReferences/ReferenceInfo.cs | 16 ---------------- .../UnusedReferences/UnusedReferencesService.cs | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index a558eb0fb2fbf..e53dfe9d526f4 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -46,21 +46,5 @@ public ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool CompilationAssemblies = compilationAssemblies; Dependencies = dependencies; } - - /// - /// Gets the compilation assemblies this reference directly brings into the compilation as well as those - /// brought in transitively. - /// - public ImmutableArray GetAllCompilationAssemblies() - { - return CompilationAssemblies - .Concat(GetTransitiveCompilationAssemblies()) - .ToImmutableArray(); - } - - private IEnumerable GetTransitiveCompilationAssemblies() - { - return Dependencies.SelectMany(dependency => dependency.GetAllCompilationAssemblies()); - } } } diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index fee65d1cd97e8..c4d2a9072d633 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -85,7 +85,7 @@ private static ImmutableHashSet AddUnusedReferences( // Determine which toplevel references have compilation assemblies in set of used assemblies. var toplevelUsedReferences = references.Where(reference => reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)); - var toplevelUsedAssemblyReferences = toplevelUsedReferences.SelectMany(reference => reference.GetAllCompilationAssemblies()); + var toplevelUsedAssemblyReferences = toplevelUsedReferences.SelectMany(reference => GetAllCompilationAssemblies(reference)); // Remove all assemblies that are brought into the compilation from those toplevel used references. When // determining transtively used references this will reduce false positives. @@ -95,7 +95,7 @@ private static ImmutableHashSet AddUnusedReferences( // Determine which transtive references have compilation assemblies in the set of remaining used assemblies. foreach (var reference in remainingReferences) { - var allCompilationAssemblies = reference.GetAllCompilationAssemblies(); + var allCompilationAssemblies = GetAllCompilationAssemblies(reference); if (allCompilationAssemblies.IsEmpty) { // We will consider References that do not contribute any assemblies to the compilation, @@ -114,7 +114,16 @@ private static ImmutableHashSet AddUnusedReferences( remainingUsedAssemblyLookup = remainingUsedAssemblyLookup.Except(allCompilationAssemblies); } - return remainingUsedAssemblyLookup; + return; + + static ImmutableArray GetAllCompilationAssemblies(ReferenceInfo reference) + { + var transitiveCompilationAssemblies = reference.Dependencies + .SelectMany(dependency => GetAllCompilationAssemblies(dependency)); + return reference.CompilationAssemblies + .Concat(transitiveCompilationAssemblies) + .ToImmutableArray(); + } } public async Task UpdateReferencesAsync( From 287d54a72e5e1b98abe442169023cd91bffb839d Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 13:56:52 -0800 Subject: [PATCH 26/57] Use mutable usedAssemblyLookup in UnusedReferencesService --- .../UnusedReferencesServiceTests.cs | 2 +- .../UnusedReferencesService.cs | 57 +++++++++---------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs index 86c5e3819b5f1..5f617cac5a1a4 100644 --- a/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs +++ b/src/EditorFeatures/Test/UnusedReferences/UnusedReferencesServiceTests.cs @@ -123,7 +123,7 @@ public async Task ApplyReferenceUpdates_MixOfChangeAndNoChangeUpdates_ChangesAre } private static ImmutableArray GetUnusedReferences(string[] usedCompilationAssemblies, params ReferenceInfo[] references) - => UnusedReferencesService.GetUnusedReferences(usedCompilationAssemblies.ToImmutableHashSet(), references.ToImmutableArray()); + => UnusedReferencesService.GetUnusedReferences(new(usedCompilationAssemblies), references.ToImmutableArray()); private static async Task> ApplyReferenceUpdatesAsync(params ReferenceUpdate[] referenceUpdates) { diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index c4d2a9072d633..6a4a8ef862c8b 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,8 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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; +using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; @@ -41,56 +42,49 @@ public async Task> GetUnusedReferencesAsync( return ImmutableArray.Empty; } - var usedAssemblyLookup = compilation.GetUsedAssemblyReferences(cancellationToken) + HashSet usedAssemblyLookup = new(compilation.GetUsedAssemblyReferences(cancellationToken) .Select(reference => reference.Display) - .OfType() - .ToImmutableHashSet(); + .OfType()); return GetUnusedReferences(usedAssemblyLookup, references); } internal static ImmutableArray GetUnusedReferences( - ImmutableHashSet usedAssemblyLookup, + HashSet usedAssemblyLookup, ImmutableArray references) { - var unusedReferences = ImmutableArray.CreateBuilder(); + var unusedReferencesBuilder = ImmutableArray.CreateBuilder(); var referencesByType = references.GroupBy(reference => reference.ReferenceType) .ToImmutableDictionary(group => group.Key); - var remainingUsedAssemblyLookup = usedAssemblyLookup; - // We process the references in order by their type. This means we favor transitive references // over direct references where possible. - foreach (var referenceType in _processingOrder) + foreach (var referenceType in _processingOrder.Where(referencesByType.ContainsKey)) { - if (!referencesByType.ContainsKey(referenceType)) - { - continue; - } - - remainingUsedAssemblyLookup = AddUnusedReferences( + AddUnusedReferences( referencesByType[referenceType].ToImmutableArray(), - remainingUsedAssemblyLookup, - unusedReferences); + usedAssemblyLookup, + unusedReferencesBuilder); } - return unusedReferences.ToImmutableArray(); + return unusedReferencesBuilder.ToImmutableArray(); } - private static ImmutableHashSet AddUnusedReferences( + private static void AddUnusedReferences( ImmutableArray references, - ImmutableHashSet usedAssemblyLookup, - ImmutableArray.Builder unusedReferences) + HashSet usedAssemblyLookup, + ImmutableArray.Builder unusedReferencesBuilder) { - // Determine which toplevel references have compilation assemblies in set of used assemblies. - var toplevelUsedReferences = references.Where(reference => - reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)); - var toplevelUsedAssemblyReferences = toplevelUsedReferences.SelectMany(reference => GetAllCompilationAssemblies(reference)); + // Determine which direct references have compilation assemblies in set of used assemblies. + var usedDirectReferences = references.Where(reference + => reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)).ToArray(); + var usedAssemblyReferences = usedDirectReferences.SelectMany(reference + => GetAllCompilationAssemblies(reference)).ToArray(); - // Remove all assemblies that are brought into the compilation from those toplevel used references. When + // Remove all assemblies that are brought into the compilation from those direct used references. When // determining transtively used references this will reduce false positives. - var remainingReferences = references.Except(toplevelUsedReferences); - var remainingUsedAssemblyLookup = usedAssemblyLookup.Except(toplevelUsedAssemblyReferences); + var remainingReferences = references.Except(usedDirectReferences).ToArray(); + usedAssemblyLookup.ExceptWith(usedAssemblyReferences); // Determine which transtive references have compilation assemblies in the set of remaining used assemblies. foreach (var reference in remainingReferences) @@ -103,15 +97,16 @@ private static ImmutableHashSet AddUnusedReferences( continue; } - if (!allCompilationAssemblies.Any(remainingUsedAssemblyLookup.Contains)) + if (!allCompilationAssemblies.Any(usedAssemblyLookup.Contains)) { // None of the assemblies brought into this compilation are in the remaining // used assemblies list, so we will consider the reference unused. - unusedReferences.Add(reference); + unusedReferencesBuilder.Add(reference); continue; } - remainingUsedAssemblyLookup = remainingUsedAssemblyLookup.Except(allCompilationAssemblies); + // Remove all assemblies that are brought into this compilation by this reference. + usedAssemblyLookup.ExceptWith(allCompilationAssemblies); } return; From 7314957005e07c8e5df3971d5f67cf7050b10641 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 14:02:32 -0800 Subject: [PATCH 27/57] Code cleanup --- src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs | 2 -- .../Dialog/RemoveUnusedReferencesDialogProvider.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index e53dfe9d526f4..b614b4124bad4 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -2,9 +2,7 @@ // 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.Linq; namespace Microsoft.CodeAnalysis.UnusedReferences { diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialogProvider.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialogProvider.cs index c785175ecfa84..b8af58b2d365e 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialogProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialogProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable enable - using System; using System.Collections.Immutable; using System.Composition; From f816a380f3b4e345af6b4bc0d9b9d7e8c596b530 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 15:23:54 -0800 Subject: [PATCH 28/57] Add clarifying comments --- .../UnusedReferences/ReferenceInfo.cs | 2 +- .../UnusedReferencesService.cs | 42 +++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index b614b4124bad4..6dcdc248e23f3 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -27,7 +27,7 @@ internal class ReferenceInfo public bool TreatAsUsed { get; } /// - /// The assembly paths that this reference directly adds to the compilation. + /// The full assembly paths that this reference directly adds to the compilation. /// public ImmutableArray CompilationAssemblies { get; } diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index 6a4a8ef862c8b..f4e13a86a1ecf 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -17,6 +17,9 @@ namespace Microsoft.CodeAnalysis.UnusedReferences [ExportWorkspaceService(typeof(IUnusedReferencesService), ServiceLayer.Default), Shared] internal class UnusedReferencesService : IUnusedReferencesService { + // We set this processing order because we want to favor transitive references when possible. + // For instance we process Projects before Packages, since a particular Package could be brought + // in transitively by a Project reference. private static readonly ReferenceType[] _processingOrder = new[] { ReferenceType.Project, @@ -75,25 +78,48 @@ private static void AddUnusedReferences( HashSet usedAssemblyLookup, ImmutableArray.Builder unusedReferencesBuilder) { - // Determine which direct references have compilation assemblies in set of used assemblies. + + // This method checks for used reference two different ways. + + // #1. We check if a reference directly brings in a used compilation assembly. + // + // references: [ PackageReference(compilationAssembly: "/libs/Used.dll") ], + // usedAssemblyLookup: [ "/libs/Used.dll" ] + // + + // #2. We check if a reference transitively brings in a used compilation assembly. + // + // references: [ + // ProjectReference( + // compilationAssembly: "/libs/Unused.dll", + // dependencies: [ PackageReference(compilationAssembly: "/libs/Used.dll") ] + // ) ] + // usedAssemblyLookup: [ "/libs/Used.dll" ] + + // Check #1. we will look at the compilation assemblies brought in directly by the + // references to see if they are used. var usedDirectReferences = references.Where(reference => reference.CompilationAssemblies.Any(usedAssemblyLookup.Contains)).ToArray(); + + // We then want to gather all the assemblies brought in directly or transitively by + // these used assemblies so that we can remove them from our lookup. var usedAssemblyReferences = usedDirectReferences.SelectMany(reference => GetAllCompilationAssemblies(reference)).ToArray(); + usedAssemblyLookup.ExceptWith(usedAssemblyReferences); - // Remove all assemblies that are brought into the compilation from those direct used references. When - // determining transtively used references this will reduce false positives. + // Now we want to look at the remaining possibly unused references to see if any of + // the assemblies they transitively bring in to the compilation are used. var remainingReferences = references.Except(usedDirectReferences).ToArray(); - usedAssemblyLookup.ExceptWith(usedAssemblyReferences); - // Determine which transtive references have compilation assemblies in the set of remaining used assemblies. foreach (var reference in remainingReferences) { + // Check #2. Get all compilation assemblies brought in by this reference so we + // can determine if any of them are used. var allCompilationAssemblies = GetAllCompilationAssemblies(reference); if (allCompilationAssemblies.IsEmpty) { - // We will consider References that do not contribute any assemblies to the compilation, - // such as Analyzer packages, as used. + // We will consider References that do not contribute any assemblies to the + // compilation, such as Analyzer packages, as used. continue; } From b501f74cffc68b92ccbf9307263a96f1e1a55496 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 15:24:21 -0800 Subject: [PATCH 29/57] Use TryGetValue instead of multiple dictionary accesses --- .../UnusedReferences/UnusedReferencesService.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs index f4e13a86a1ecf..77ead3d8904bf 100644 --- a/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs +++ b/src/Features/Core/Portable/UnusedReferences/UnusedReferencesService.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -62,10 +62,15 @@ internal static ImmutableArray GetUnusedReferences( // We process the references in order by their type. This means we favor transitive references // over direct references where possible. - foreach (var referenceType in _processingOrder.Where(referencesByType.ContainsKey)) + foreach (var referenceType in _processingOrder) { + if (!referencesByType.TryGetValue(referenceType, out var referencesForReferenceType)) + { + continue; + } + AddUnusedReferences( - referencesByType[referenceType].ToImmutableArray(), + referencesForReferenceType.ToImmutableArray(), usedAssemblyLookup, unusedReferencesBuilder); } From a13c308ff6f44e84b94292fe3f5685cd967dc318 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 16:08:47 -0800 Subject: [PATCH 30/57] Extract out a CommandHelpers class of common code. --- .../VisualStudioDiagnosticAnalyzerService.cs | 102 +---------------- .../RemoveUnusedReferencesCommandHandler.cs | 107 ++---------------- .../VisualStudioCommandHandlerHelpers.cs | 102 +++++++++++++++++ 3 files changed, 117 insertions(+), 194 deletions(-) create mode 100644 src/VisualStudio/Core/Def/Implementation/Utilities/VisualStudioCommandHandlerHelpers.cs diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs index 334417804d6d6..bf54a96c059fc 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs @@ -7,10 +7,7 @@ using System.Collections.Immutable; using System.ComponentModel.Composition; using System.ComponentModel.Design; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -23,6 +20,7 @@ using Roslyn.Utilities; using Task = System.Threading.Tasks.Task; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics { @@ -68,24 +66,8 @@ public void Initialize(IServiceProvider serviceProvider) var menuCommandService = (IMenuCommandService)_serviceProvider.GetService(typeof(IMenuCommandService)); if (menuCommandService != null) { - AddCommand(menuCommandService, RunCodeAnalysisForSelectedProjectCommandId, VSConstants.VSStd2K, OnRunCodeAnalysisForSelectedProject, OnRunCodeAnalysisForSelectedProjectStatus); - AddCommand(menuCommandService, ID.RoslynCommands.RunCodeAnalysisForProject, Guids.RoslynGroupId, OnRunCodeAnalysisForSelectedProject, OnRunCodeAnalysisForSelectedProjectStatus); - } - - return; - - // Local functions - static OleMenuCommand AddCommand( - IMenuCommandService menuCommandService, - int commandId, - Guid commandGroup, - EventHandler invokeHandler, - EventHandler beforeQueryStatus) - { - var commandIdWithGroupId = new CommandID(commandGroup, commandId); - var command = new OleMenuCommand(invokeHandler, delegate { }, beforeQueryStatus, commandIdWithGroupId); - menuCommandService.AddCommand(command); - return command; + VisualStudioCommandHandlerHelpers.AddCommand(menuCommandService, RunCodeAnalysisForSelectedProjectCommandId, VSConstants.VSStd2K, OnRunCodeAnalysisForSelectedProject, OnRunCodeAnalysisForSelectedProjectStatus); + VisualStudioCommandHandlerHelpers.AddCommand(menuCommandService, ID.RoslynCommands.RunCodeAnalysisForProject, Guids.RoslynGroupId, OnRunCodeAnalysisForSelectedProject, OnRunCodeAnalysisForSelectedProjectStatus); } } @@ -155,7 +137,7 @@ private void OnRunCodeAnalysisForSelectedProjectStatus(object sender, EventArgs // We hook up the "Run Code Analysis" menu commands for CPS based managed projects. // These commands are already hooked up for csproj based projects in StanCore, but those will eventually go away. - var visible = TryGetSelectedProjectHierarchy(out var hierarchy) && + var visible = VisualStudioCommandHandlerHelpers.TryGetSelectedProjectHierarchy(_serviceProvider, out var hierarchy) && hierarchy.IsCapabilityMatch("CPS") && hierarchy.IsCapabilityMatch(".NET"); var enabled = false; @@ -169,7 +151,7 @@ private void OnRunCodeAnalysisForSelectedProjectStatus(object sender, EventArgs command.Text = string.Format(ServicesVSResources.Run_Code_Analysis_on_0, project.Name); } - enabled = !IsBuildActive(); + enabled = !VisualStudioCommandHandlerHelpers.IsBuildActive(_serviceProvider); } if (command.Visible != visible) @@ -184,7 +166,7 @@ private void OnRunCodeAnalysisForSelectedProjectStatus(object sender, EventArgs private void OnRunCodeAnalysisForSelectedProject(object sender, EventArgs args) { - if (TryGetSelectedProjectHierarchy(out var hierarchy)) + if (VisualStudioCommandHandlerHelpers.TryGetSelectedProjectHierarchy(_serviceProvider, out var hierarchy)) { RunAnalyzers(hierarchy); } @@ -278,78 +260,6 @@ void HandleProjectsWithDisabledAnalysis() return null; } - private bool TryGetSelectedProjectHierarchy([NotNullWhen(returnValue: true)] out IVsHierarchy? hierarchy) - { - hierarchy = null; - - // Get the DTE service and make sure there is an open solution - if (!(_serviceProvider?.GetService(typeof(EnvDTE.DTE)) is EnvDTE.DTE dte) || - dte.Solution == null) - { - return false; - } - - var selectionHierarchy = IntPtr.Zero; - var selectionContainer = IntPtr.Zero; - - // Get the current selection in the shell - if (_serviceProvider.GetService(typeof(SVsShellMonitorSelection)) is IVsMonitorSelection monitorSelection) - { - try - { - monitorSelection.GetCurrentSelection(out selectionHierarchy, out var itemId, out var multiSelect, out selectionContainer); - if (selectionHierarchy != IntPtr.Zero) - { - hierarchy = Marshal.GetObjectForIUnknown(selectionHierarchy) as IVsHierarchy; - Debug.Assert(hierarchy != null); - return hierarchy != null; - } - } - catch (Exception) - { - // If anything went wrong, just ignore it - } - finally - { - // Make sure we release the COM pointers in any case - if (selectionHierarchy != IntPtr.Zero) - { - Marshal.Release(selectionHierarchy); - } - - if (selectionContainer != IntPtr.Zero) - { - Marshal.Release(selectionContainer); - } - } - } - - return false; - } - - private bool IsBuildActive() - { - // Using KnownUIContexts is faster in case when SBM's package was not loaded yet - if (KnownUIContexts.SolutionBuildingContext != null) - { - return KnownUIContexts.SolutionBuildingContext.IsActive; - } - else - { - // Unlikely case that above service is not available, let's try Solution Build Manager - if (_serviceProvider?.GetService(typeof(SVsSolutionBuildManager)) is IVsSolutionBuildManager buildManager) - { - buildManager.QueryBuildManagerBusy(out var buildBusy); - return buildBusy != 0; - } - else - { - Debug.Fail("Unable to determine whether build is active or not"); - return true; - } - } - } - private sealed class StatusBarUpdater : IDisposable { private readonly IVsStatusbar _statusBar; diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index 6c8edfb6d0017..fbc4804b80bdf 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -6,20 +6,19 @@ using System.Collections.Immutable; using System.ComponentModel.Design; using System.Composition; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.Dialog; using Microsoft.VisualStudio.LanguageServices.Implementation.UnusedReferences.ProjectAssets; +using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -36,7 +35,7 @@ internal sealed class RemoveUnusedReferencesCommandHandler private readonly IReferenceCleanupService _referenceCleanupService; private readonly IUnusedReferencesService _unusedReferencesService; private readonly RemoveUnusedReferencesDialogProvider _unusedReferenceDialogProvider; - private readonly VisualStudioWorkspaceImpl _workspace; + private readonly VisualStudioWorkspace _workspace; private readonly IVsHierarchyItemManager _vsHierarchyItemManager; private readonly IUIThreadOperationExecutor _threadOperationExecutor; private IServiceProvider? _serviceProvider; @@ -47,7 +46,7 @@ public RemoveUnusedReferencesCommandHandler( RemoveUnusedReferencesDialogProvider unusedReferenceDialogProvider, IVsHierarchyItemManager vsHierarchyItemManager, IUIThreadOperationExecutor threadOperationExecutor, - VisualStudioWorkspaceImpl workspace) + VisualStudioWorkspace workspace) { _unusedReferenceDialogProvider = unusedReferenceDialogProvider; _vsHierarchyItemManager = vsHierarchyItemManager; @@ -68,23 +67,7 @@ public void Initialize(IServiceProvider serviceProvider) var menuCommandService = (IMenuCommandService)_serviceProvider.GetService(typeof(IMenuCommandService)); if (menuCommandService != null) { - AddCommand(menuCommandService, ID.RoslynCommands.RemoveUnusedReferences, Guids.RoslynGroupId, OnRemoveUnusedReferencesForSelectedProject, OnRemoveUnusedReferencesForSelectedProjectStatus); - } - - return; - - // Local functions - static OleMenuCommand AddCommand( - IMenuCommandService menuCommandService, - int commandId, - Guid commandGroup, - EventHandler invokeHandler, - EventHandler beforeQueryStatus) - { - var commandIdWithGroupId = new CommandID(commandGroup, commandId); - var command = new OleMenuCommand(invokeHandler, delegate { }, beforeQueryStatus, commandIdWithGroupId); - menuCommandService.AddCommand(command); - return command; + VisualStudioCommandHandlerHelpers.AddCommand(menuCommandService, ID.RoslynCommands.RemoveUnusedReferences, Guids.RoslynGroupId, OnRemoveUnusedReferencesForSelectedProject, OnRemoveUnusedReferencesForSelectedProjectStatus); } } @@ -93,7 +76,7 @@ private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, Eve var command = (OleMenuCommand)sender; // Only show the "Remove Unused Reference" menu commands for CPS based managed projects. - var visible = TryGetSelectedProjectHierarchy(out var hierarchy) && + var visible = VisualStudioCommandHandlerHelpers.TryGetSelectedProjectHierarchy(_serviceProvider, out var hierarchy) && hierarchy.IsCapabilityMatch("CPS") && hierarchy.IsCapabilityMatch(".NET") && _workspace.Options.GetOption(FeatureOnOffOptions.OfferRemoveUnusedReferences); @@ -101,7 +84,7 @@ private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, Eve if (visible) { - enabled = !IsBuildActive(); + enabled = !VisualStudioCommandHandlerHelpers.IsBuildActive(_serviceProvider); } if (command.Visible != visible) @@ -116,7 +99,7 @@ private void OnRemoveUnusedReferencesForSelectedProjectStatus(object sender, Eve private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs args) { - if (TryGetSelectedProjectHierarchy(out var hierarchy)) + if (VisualStudioCommandHandlerHelpers.TryGetSelectedProjectHierarchy(_serviceProvider, out var hierarchy)) { Project? project = null; ImmutableArray referenceUpdates = default; @@ -182,7 +165,7 @@ private void OnRemoveUnusedReferencesForSelectedProject(object sender, EventArgs return (null, ImmutableArray.Empty); } - var project = _workspace.CurrentSolution.GetProject(projectId)!; + var project = _workspace.CurrentSolution.GetRequiredProject(projectId); var unusedReferences = GetUnusedReferencesForProject(project, projectAssetsFile!, targetFrameworkMoniker, cancellationToken); return (project, unusedReferences); @@ -243,77 +226,5 @@ private static bool TryGetPropertyValue(IVsHierarchy hierarchy, string propertyN return ErrorHandler.Succeeded(storage.GetPropertyValue(propertyName, null, (uint)_PersistStorageType.PST_PROJECT_FILE, out propertyValue)); } - - private bool TryGetSelectedProjectHierarchy([NotNullWhen(returnValue: true)] out IVsHierarchy? hierarchy) - { - hierarchy = null; - - // Get the DTE service and make sure there is an open solution - if (_serviceProvider?.GetService(typeof(EnvDTE.DTE)) is not EnvDTE.DTE dte || - dte.Solution == null) - { - return false; - } - - var selectionHierarchy = IntPtr.Zero; - var selectionContainer = IntPtr.Zero; - - // Get the current selection in the shell - if (_serviceProvider.GetService(typeof(SVsShellMonitorSelection)) is IVsMonitorSelection monitorSelection) - { - try - { - monitorSelection.GetCurrentSelection(out selectionHierarchy, out var itemId, out var multiSelect, out selectionContainer); - if (selectionHierarchy != IntPtr.Zero) - { - hierarchy = Marshal.GetObjectForIUnknown(selectionHierarchy) as IVsHierarchy; - Debug.Assert(hierarchy != null); - return hierarchy != null; - } - } - catch (Exception) - { - // If anything went wrong, just ignore it - } - finally - { - // Make sure we release the COM pointers in any case - if (selectionHierarchy != IntPtr.Zero) - { - Marshal.Release(selectionHierarchy); - } - - if (selectionContainer != IntPtr.Zero) - { - Marshal.Release(selectionContainer); - } - } - } - - return false; - } - - private bool IsBuildActive() - { - // Using KnownUIContexts is faster in case when SBM's package was not loaded yet - if (KnownUIContexts.SolutionBuildingContext != null) - { - return KnownUIContexts.SolutionBuildingContext.IsActive; - } - else - { - // Unlikely case that above service is not available, let's try Solution Build Manager - if (_serviceProvider?.GetService(typeof(SVsSolutionBuildManager)) is IVsSolutionBuildManager buildManager) - { - buildManager.QueryBuildManagerBusy(out var buildBusy); - return buildBusy != 0; - } - else - { - Debug.Fail("Unable to determine whether build is active or not"); - return true; - } - } - } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Utilities/VisualStudioCommandHandlerHelpers.cs b/src/VisualStudio/Core/Def/Implementation/Utilities/VisualStudioCommandHandlerHelpers.cs new file mode 100644 index 0000000000000..d5c0eec9ef1ba --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Utilities/VisualStudioCommandHandlerHelpers.cs @@ -0,0 +1,102 @@ +// 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; +using System.ComponentModel.Design; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities +{ + internal static class VisualStudioCommandHandlerHelpers + { + public static OleMenuCommand AddCommand( + IMenuCommandService menuCommandService, + int commandId, + Guid commandGroup, + EventHandler invokeHandler, + EventHandler beforeQueryStatus) + { + var commandIdWithGroupId = new CommandID(commandGroup, commandId); + var command = new OleMenuCommand(invokeHandler, delegate { }, beforeQueryStatus, commandIdWithGroupId); + menuCommandService.AddCommand(command); + return command; + } + + public static bool TryGetSelectedProjectHierarchy(IServiceProvider? serviceProvider, [NotNullWhen(returnValue: true)] out IVsHierarchy? hierarchy) + { + hierarchy = null; + + // Get the DTE service and make sure there is an open solution + if (serviceProvider?.GetService(typeof(EnvDTE.DTE)) is not EnvDTE.DTE dte || + dte.Solution == null) + { + return false; + } + + var selectionHierarchy = IntPtr.Zero; + var selectionContainer = IntPtr.Zero; + + // Get the current selection in the shell + if (serviceProvider.GetService(typeof(SVsShellMonitorSelection)) is IVsMonitorSelection monitorSelection) + { + try + { + monitorSelection.GetCurrentSelection(out selectionHierarchy, out var itemId, out var multiSelect, out selectionContainer); + if (selectionHierarchy != IntPtr.Zero) + { + hierarchy = Marshal.GetObjectForIUnknown(selectionHierarchy) as IVsHierarchy; + Debug.Assert(hierarchy != null); + return hierarchy != null; + } + } + catch (Exception) + { + // If anything went wrong, just ignore it + } + finally + { + // Make sure we release the COM pointers in any case + if (selectionHierarchy != IntPtr.Zero) + { + Marshal.Release(selectionHierarchy); + } + + if (selectionContainer != IntPtr.Zero) + { + Marshal.Release(selectionContainer); + } + } + } + + return false; + } + + public static bool IsBuildActive(IServiceProvider? serviceProvider) + { + // Using KnownUIContexts is faster in case when SBM's package was not loaded yet + if (KnownUIContexts.SolutionBuildingContext != null) + { + return KnownUIContexts.SolutionBuildingContext.IsActive; + } + else + { + // Unlikely case that above service is not available, let's try Solution Build Manager + if (serviceProvider?.GetService(typeof(SVsSolutionBuildManager)) is IVsSolutionBuildManager buildManager) + { + buildManager.QueryBuildManagerBusy(out var buildBusy); + return buildBusy != 0; + } + else + { + Debug.Fail("Unable to determine whether build is active or not"); + return true; + } + } + } + } +} From a0b7522946a90ea37f0d0c3cb44debc37a2274a9 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Fri, 18 Dec 2020 16:58:44 -0800 Subject: [PATCH 31/57] Fix accessibility of Actions ComboBox --- .../Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs index 3fa4842f68f02..a151491eef397 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/UnusedReferencesTableProvider.ColumnDefinitions.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.ComponentModel.Composition; using System.Windows; +using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Documents; using Microsoft.CodeAnalysis; @@ -293,6 +294,8 @@ public override bool TryCreateColumnContent(ITableEntryHandle entry, bool single ItemsSource = new[] { ServicesVSResources.Keep, ServicesVSResources.Remove } }; + combobox.SetValue(AutomationProperties.NameProperty, ServicesVSResources.Action); + if (entry.TryGetValue(UnusedReferencesTableKeyNames.UpdateAction, out UpdateAction action)) { combobox.SelectedItem = action switch From cfd230b561c718eac73b247b199b39412f38ebd1 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 6 Jan 2021 09:52:06 -0800 Subject: [PATCH 32/57] Update string resources --- .../Core/Def/ServicesVSResources.resx | 59 ++++++++++--------- .../Core/Def/xlf/ServicesVSResources.cs.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.de.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.es.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.fr.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.it.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.ja.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.ko.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.pl.xlf | 10 ++-- .../Def/xlf/ServicesVSResources.pt-BR.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.ru.xlf | 10 ++-- .../Core/Def/xlf/ServicesVSResources.tr.xlf | 10 ++-- .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 10 ++-- .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 10 ++-- 14 files changed, 95 insertions(+), 94 deletions(-) diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index d7f131c91e63c..fca12cb4ae113 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1,17 +1,17 @@ - @@ -1607,6 +1607,7 @@ I agree to all of the foregoing: Action + Action to perform on an unused reference, such as remove or keep Assemblies @@ -1630,10 +1631,10 @@ I agree to all of the foregoing: Remove Unused References - Analyzing project references. + Analyzing project references... - Updating project references. + Updating project references... No unused references were found. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 9ed30b8a05597..b38f7a7727c4c 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 6c851051537c2..88dab78842b01 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 4307ac8aa0e55..1375a83cbadcd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index d8c591aeca2c3..e1d568912a934 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 08716ae9ceba2..c94c85fa62a5e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 59bc989efa9b6..2e930318432c1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 2ae22f8eaad78..86ce9c6f5dd6a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index d82d6a5d858e8..5e82018bd68a8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index bc849decf16a6..a53c34c15f74f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index c9ddde5ffc32f..24e12e46774e9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 96a5d6dbf83e6..3df09b449611a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 199c9dceeb7dc..7993edfd12d6f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 08d5f342e9750..05dbd1c814ff0 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -20,7 +20,7 @@ Action Action - + Action to perform on an unused reference, such as remove or keep _Add @@ -68,8 +68,8 @@ - Analyzing project references. - Analyzing project references. + Analyzing project references... + Analyzing project references... @@ -973,8 +973,8 @@ - Updating project references. - Updating project references. + Updating project references... + Updating project references... From 30eebafbb7134e2297fd2693e9bc0e8a4ab1e4ba Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 6 Jan 2021 09:52:22 -0800 Subject: [PATCH 33/57] Update parameter name for clarity --- .../Dialog/RemoveUnusedReferencesDialog.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs index c91cd30c3c798..b7b447b59c4eb 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/Dialog/RemoveUnusedReferencesDialog.xaml.cs @@ -17,11 +17,11 @@ internal partial class RemoveUnusedReferencesDialog : DialogWindow public string Apply => ServicesVSResources.Apply; public string Cancel => ServicesVSResources.Cancel; - public RemoveUnusedReferencesDialog(FrameworkElement element) + public RemoveUnusedReferencesDialog(FrameworkElement tableControl) { InitializeComponent(); - TablePanel.Child = element; + TablePanel.Child = tableControl; } private void ApplyButton_Click(object sender, RoutedEventArgs e) From ab85d797c6ae5f0c112d462fbc01eb43928aa14c Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Wed, 6 Jan 2021 10:47:46 -0800 Subject: [PATCH 34/57] Updated command placement and cleaned up Commands.vsct --- src/VisualStudio/Core/Def/Commands.vsct | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/VisualStudio/Core/Def/Commands.vsct b/src/VisualStudio/Core/Def/Commands.vsct index c9dd185551fc5..422b93c7d0bfd 100644 --- a/src/VisualStudio/Core/Def/Commands.vsct +++ b/src/VisualStudio/Core/Def/Commands.vsct @@ -20,10 +20,6 @@ - - - - @@ -66,10 +62,6 @@ - - - - @@ -407,10 +399,9 @@ -