diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/NuGet.PackageManagement.VisualStudio.csproj b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/NuGet.PackageManagement.VisualStudio.csproj index 18fc8c6460d..87387d3c6c0 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/NuGet.PackageManagement.VisualStudio.csproj +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/NuGet.PackageManagement.VisualStudio.csproj @@ -43,6 +43,7 @@ + @@ -66,7 +67,7 @@ - + diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemReferenceReader.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemReferenceReader.cs new file mode 100644 index 00000000000..599863f3a3f --- /dev/null +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemReferenceReader.cs @@ -0,0 +1,135 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft; +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.ProjectSystem.Properties; +using Microsoft.VisualStudio.ProjectSystem.References; +using Microsoft.VisualStudio.Threading; +using NuGet.Frameworks; +using NuGet.LibraryModel; +using NuGet.ProjectManagement; +using NuGet.ProjectModel; +using NuGet.VisualStudio; + +namespace NuGet.PackageManagement.VisualStudio +{ + /// + /// Reference reader implementation for the core project system in the integrated development environment (IDE). + /// + internal class CpsProjectSystemReferenceReader + : IProjectSystemReferencesReader + { + private readonly IVsProjectAdapter _vsProjectAdapter; + private readonly IVsProjectThreadingService _threadingService; + private readonly AsyncLazy _unconfiguredProject; + + public CpsProjectSystemReferenceReader( + IVsProjectAdapter vsProjectAdapter, + IVsProjectThreadingService threadingService) + { + Assumes.Present(vsProjectAdapter); + Assumes.Present(threadingService); + + _vsProjectAdapter = vsProjectAdapter; + _threadingService = threadingService; + _unconfiguredProject = new AsyncLazy(async () => + { + await _threadingService.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var context = _vsProjectAdapter.Project as IVsBrowseObjectContext; + if (context == null) + { + // VC implements this on their DTE.Project.Object + context = _vsProjectAdapter.Project.Object as IVsBrowseObjectContext; + } + return context?.UnconfiguredProject; + }, threadingService.JoinableTaskFactory); + } + + public async Task> GetProjectReferencesAsync( + Common.ILogger logger, CancellationToken _) + { + var unconfiguredProject = await _unconfiguredProject.GetValueAsync(); + IBuildDependencyProjectReferencesService service = await GetProjectReferencesService(unconfiguredProject); + + if (service == null) + { + return Enumerable.Empty(); + } + + var results = new List(); + var hasMissingReferences = false; + + foreach (IUnresolvedBuildDependencyProjectReference projectReference in await service.GetUnresolvedReferencesAsync()) + { + try + { + if (await projectReference.GetReferenceOutputAssemblyAsync()) + { + string childProjectPath = projectReference.EvaluatedIncludeAsFullPath; + var projectRestoreReference = new ProjectRestoreReference() + { + ProjectPath = childProjectPath, + ProjectUniqueName = childProjectPath + }; + + results.Add(projectRestoreReference); + } + } + catch (Exception ex) + { + hasMissingReferences = true; + logger.LogDebug(ex.ToString()); + } + } + + if (hasMissingReferences) + { + // Log a generic message once per project if any items could not be resolved. + // In most cases this can be ignored, but in the rare case where the unresolved + // item is actually a project the restore result will be incomplete. + var message = string.Format( + CultureInfo.CurrentCulture, + Strings.UnresolvedItemDuringProjectClosureWalk, + _vsProjectAdapter.UniqueName); + + logger.LogVerbose(message); + } + + return results; + } + + /// + /// Gets the project reference service for the suggested configured project if available, otherwise. + /// + private static async Task GetProjectReferencesService(UnconfiguredProject unconfiguredProject) + { + IBuildDependencyProjectReferencesService service = null; + + if (unconfiguredProject != null) + { + ConfiguredProject configuredProject = await unconfiguredProject.GetSuggestedConfiguredProjectAsync(); + + if (configuredProject != null) + { + service = configuredProject.Services.ProjectReferences; + } + } + + return service; + } + + public Task> GetPackageReferencesAsync( + NuGetFramework targetFramework, CancellationToken _) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/NetCoreProjectSystemServices.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemServices.cs similarity index 93% rename from src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/NetCoreProjectSystemServices.cs rename to src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemServices.cs index 06b5c26cf9c..d68445636a2 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/NetCoreProjectSystemServices.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/ProjectServices/CpsProjectSystemServices.cs @@ -11,10 +11,10 @@ namespace NuGet.PackageManagement.VisualStudio /// /// Represent net core project systems in visual studio. /// - internal class NetCoreProjectSystemServices : + internal class CpsProjectSystemServices : INuGetProjectServices { - public NetCoreProjectSystemServices( + public CpsProjectSystemServices( IVsProjectAdapter vsProjectAdapter, Lazy scriptExecutor) { diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProjectProvider.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProjectProvider.cs index 7e04a48078b..cfc781a3ee4 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProjectProvider.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/CpsPackageReferenceProjectProvider.cs @@ -88,7 +88,7 @@ await vsProject.IsCapabilityMatchAsync(NuGet.VisualStudio.IDE.ProjectCapabilitie var fullProjectPath = vsProject.FullProjectPath; var unconfiguredProject = GetUnconfiguredProject(vsProject.Project); - var projectServices = new NetCoreProjectSystemServices(vsProject, _scriptExecutor); + var projectServices = new CpsProjectSystemServices(vsProject, _scriptExecutor); return new CpsPackageReferenceProject( vsProject.ProjectName, diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/VsMSBuildProjectSystemServices.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/VsMSBuildProjectSystemServices.cs index 83509702c7b..62832ec47c5 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/VsMSBuildProjectSystemServices.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Projects/VsMSBuildProjectSystemServices.cs @@ -64,7 +64,9 @@ public VsMSBuildProjectSystemServices( _vsProjectSystem = vsProjectSystem; _threadingService = threadingService; - ReferencesReader = new VsCoreProjectSystemReferenceReader(vsProjectAdapter, threadingService); + ReferencesReader = vsProjectSystem is CpsProjectSystem ? + new CpsProjectSystemReferenceReader(vsProjectAdapter, _threadingService) : + new VsCoreProjectSystemReferenceReader(vsProjectAdapter, _threadingService); ScriptService = new VsProjectScriptHostService(vsProjectAdapter, scriptExecutor); } }