From 20a5cde373d47d637c21754e7b8016112c572079 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Fri, 16 Aug 2024 14:21:19 -0700 Subject: [PATCH 1/2] Fix issue where output path set in construction never updated the solution or project update state --- .../Workspace/ProjectSystem/ProjectSystemProject.cs | 4 +--- .../Workspace/ProjectSystem/ProjectSystemProjectFactory.cs | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs index 7cc8173e5b0e4..622632ae2063e 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs @@ -149,8 +149,7 @@ internal ProjectSystemProject( string assemblyName, CompilationOptions? compilationOptions, string? filePath, - ParseOptions? parseOptions, - string? compilationOutputAssemblyFilePath) + ParseOptions? parseOptions) { _projectSystemProjectFactory = projectSystemProjectFactory; _hostInfo = hostInfo; @@ -197,7 +196,6 @@ internal ProjectSystemProject( _compilationOptions = compilationOptions; _filePath = filePath; _parseOptions = parseOptions; - _compilationOutputAssemblyFilePath = compilationOutputAssemblyFilePath; var watchedDirectories = GetWatchedDirectories(language, filePath); _documentFileChangeContext = _projectSystemProjectFactory.FileChangeWatcher.CreateContext(watchedDirectories); diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs index 59977f409c441..7e23dcce25ad5 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs @@ -102,8 +102,7 @@ public async Task CreateAndAddToWorkspaceAsync(string proj assemblyName, creationInfo.CompilationOptions, creationInfo.FilePath, - creationInfo.ParseOptions, - creationInfo.CompilationOutputAssemblyFilePath); + creationInfo.ParseOptions); var versionStamp = creationInfo.FilePath != null ? VersionStamp.Create(File.GetLastWriteTimeUtc(creationInfo.FilePath)) @@ -164,6 +163,10 @@ await ApplyChangeToWorkspaceAsync(w => onAfterUpdate: null); }).ConfigureAwait(false); + // Set this value early after solution is created so it is available to Razor. This will get updated + // when the command line is set, but we want a non-null value to be available as soon as possible. + project.CompilationOutputAssemblyFilePath = creationInfo.CompilationOutputAssemblyFilePath; + return project; } From a559dd3af1da5fc41a5c53e7aefcf3625adbbc28 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Fri, 16 Aug 2024 16:23:35 -0700 Subject: [PATCH 2/2] Review feedback --- .../ProjectSystemProjectFactoryTests.vb | 38 +++++++++++++++++++ .../ProjectSystemProjectFactory.cs | 5 +++ 2 files changed, 43 insertions(+) create mode 100644 src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb new file mode 100644 index 0000000000000..3b744dfa4fd93 --- /dev/null +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb @@ -0,0 +1,38 @@ +' 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. + +Imports System.Collections.Immutable +Imports System.Threading +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem +Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework +Imports Roslyn.Test.Utilities + +Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim + <[UseExportProvider]> + Public Class ProjectSystemProjectFactoryTests + + Public Async Function ProjectInstantiatedWithCompilationOutputAssemblyFilePathCanBeChanged() As Task + Using environment = New TestEnvironment() + Dim creationInfo = New VisualStudioProjectCreationInfo() + creationInfo.CompilationOutputAssemblyFilePath = "C:\output\project.dll" + Dim project1 = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( + "project1", LanguageNames.CSharp, creationInfo, CancellationToken.None) + + Dim projectInSolution = environment.Workspace.CurrentSolution.GetProject(project1.Id) + + Assert.Equal(creationInfo.CompilationOutputAssemblyFilePath, projectInSolution.CompilationOutputInfo.AssemblyPath) + + ' Change the path and ensure it's updated + Dim newOutputPath = "C:\output\new\project.dll" + project1.CompilationOutputAssemblyFilePath = newOutputPath + + Dim newProjectInSolution As Project = environment.Workspace.CurrentSolution.GetProject(project1.Id) + Assert.Equal(newOutputPath, newProjectInSolution.CompilationOutputInfo.AssemblyPath) + End Using + End Function + End Class +End Namespace diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs index 7e23dcce25ad5..470a62bd9b5e8 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProjectFactory.cs @@ -165,6 +165,11 @@ await ApplyChangeToWorkspaceAsync(w => // Set this value early after solution is created so it is available to Razor. This will get updated // when the command line is set, but we want a non-null value to be available as soon as possible. + // + // Set the property in a batch; if we set the property directly we'll be taking a synchronous lock here and + // potentially block up thread pool threads. Doing this in a batch means the global lock will be acquired asynchronously. + var disposableBatchScope = await project.CreateBatchScopeAsync(CancellationToken.None).ConfigureAwait(false); + await using var _ = disposableBatchScope.ConfigureAwait(false); project.CompilationOutputAssemblyFilePath = creationInfo.CompilationOutputAssemblyFilePath; return project;