From cfb9c47aee235426278665850043083f9ceb80c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Fri, 7 Feb 2020 11:27:34 +0200 Subject: [PATCH 1/2] Adds support for aliases on both ProjectReference and Reference --- .../ProjectFileInfo.ProjectData.cs | 40 ++++++++++++++----- .../ProjectFile/ProjectFileInfo.cs | 1 + src/OmniSharp.MSBuild/ProjectManager.cs | 21 +++++++++- .../ExternAlias.App/ExternAlias.App.csproj | 4 -- .../ExternAlias.App2/ExternAlias.App2.csproj | 15 +++++++ .../ExternAlias/ExternAlias.App2/Program.cs | 14 +++++++ .../test-projects/ExternAlias/ExternAlias.sln | 14 +++++++ .../ProjectFileInfoTests.cs | 28 +++++++++++-- 8 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 test-assets/test-projects/ExternAlias/ExternAlias.App2/ExternAlias.App2.csproj create mode 100644 test-assets/test-projects/ExternAlias/ExternAlias.App2/Program.cs diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs index ad470bda02..1e6aa214ee 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs @@ -51,6 +51,7 @@ private class ProjectData public ImmutableArray AdditionalFiles { get; } public RuleSet RuleSet { get; } public ImmutableDictionary ReferenceAliases { get; } + public ImmutableDictionary ProjectReferenceAliases { get; } public bool TreatWarningsAsErrors { get; } public string DefaultNamespace { get; } @@ -68,6 +69,7 @@ private ProjectData() Analyzers = ImmutableArray.Empty; AdditionalFiles = ImmutableArray.Empty; ReferenceAliases = ImmutableDictionary.Empty; + ProjectReferenceAliases = ImmutableDictionary.Empty; } private ProjectData( @@ -148,7 +150,8 @@ private ProjectData( bool treatWarningsAsErrors, string defaultNamespace, RuleSet ruleset, - ImmutableDictionary referenceAliases) + ImmutableDictionary referenceAliases, + ImmutableDictionary projectReferenceAliases) : this(guid, name, assemblyName, targetPath, outputPath, intermediateOutputPath, projectAssetsFile, configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, checkForOverflowUnderflow, documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, ruleset) @@ -160,6 +163,7 @@ private ProjectData( Analyzers = analyzers.EmptyIfDefault(); AdditionalFiles = additionalFiles.EmptyIfDefault(); ReferenceAliases = referenceAliases; + ProjectReferenceAliases = projectReferenceAliases; } public static ProjectData Create(MSB.Evaluation.Project project) @@ -243,8 +247,24 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance) var sourceFiles = GetFullPaths( projectInstance.GetItems(ItemNames.Compile), filter: FileNameIsNotGenerated); - var projectReferences = GetFullPaths( - projectInstance.GetItems(ItemNames.ProjectReference), filter: IsCSharpProject); + var projectReferences = ImmutableArray.CreateBuilder(); + var projectReferenceAliases = ImmutableDictionary.CreateBuilder(); + var projectReferencesAdded = new HashSet(); + foreach (var projectReferenceItem in projectInstance.GetItems(ItemNames.ProjectReference)) + { + var fullPath = projectReferenceItem.GetMetadataValue(MetadataNames.FullPath); + + if (IsCSharpProject(fullPath) && projectReferencesAdded.Add(fullPath)) + { + projectReferences.Add(fullPath); + + var aliases = projectReferenceItem.GetMetadataValue(MetadataNames.Aliases); + if (!string.IsNullOrEmpty(aliases)) + { + projectReferenceAliases[fullPath] = aliases; + } + } + } var references = ImmutableArray.CreateBuilder(); var referenceAliases = ImmutableDictionary.CreateBuilder(); @@ -272,11 +292,12 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance) if (!string.IsNullOrEmpty(fullPath)) { references.Add(fullPath); - } - var aliases = referencePathItem.GetMetadataValue(MetadataNames.Aliases); - if(!string.IsNullOrEmpty(aliases)) - { - referenceAliases[referencePathItem.EvaluatedInclude] = aliases; + + var aliases = referencePathItem.GetMetadataValue(MetadataNames.Aliases); + if (!string.IsNullOrEmpty(aliases)) + { + referenceAliases[fullPath] = aliases; + } } } @@ -289,7 +310,8 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance) configuration, platform, targetFramework, targetFrameworks, outputKind, languageVersion, nullableContextOptions, allowUnsafeCode, checkForOverflowUnderflow, documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, - sourceFiles, projectReferences, references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, defaultNamespace, ruleset, referenceAliases.ToImmutableDictionary()); + sourceFiles, projectReferences.ToImmutable(), references.ToImmutable(), packageReferences, analyzers, additionalFiles, treatWarningsAsErrors, defaultNamespace, ruleset, + referenceAliases.ToImmutableDictionary(), projectReferenceAliases.ToImmutable()); } private static RuleSet ResolveRulesetIfAny(MSB.Execution.ProjectInstance projectInstance) diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs index 085b219524..1d7177847b 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs @@ -53,6 +53,7 @@ internal partial class ProjectFileInfo public ImmutableArray Analyzers => _data.Analyzers; public ImmutableArray AdditionalFiles => _data.AdditionalFiles; public ImmutableDictionary ReferenceAliases => _data.ReferenceAliases; + public ImmutableDictionary ProjectReferenceAliases => _data.ProjectReferenceAliases; public bool TreatWarningsAsErrors => _data.TreatWarningsAsErrors; public string DefaultNamespace => _data.DefaultNamespace; diff --git a/src/OmniSharp.MSBuild/ProjectManager.cs b/src/OmniSharp.MSBuild/ProjectManager.cs index f0ff0e0f4b..6be793bfec 100644 --- a/src/OmniSharp.MSBuild/ProjectManager.cs +++ b/src/OmniSharp.MSBuild/ProjectManager.cs @@ -604,7 +604,24 @@ private void UpdateProjectReferences(Project project, ImmutableArray pro continue; } - var projectReference = new ProjectReference(referencedProject.Id); + ImmutableArray aliases = default; + if (_projectFiles.TryGetValue(project.FilePath, out var projectFileInfo)) + { + if (projectFileInfo.ProjectReferenceAliases.TryGetValue(projectReferencePath, out var projectReferenceAliases)) + { + if (!string.IsNullOrEmpty(projectReferenceAliases)) + { + aliases = projectReferenceAliases.Split(';').ToImmutableArray(); + _logger.LogDebug($"Setting aliases: {projectReferencePath}, {projectReferenceAliases} "); + } + } + } + else + { + _logger.LogDebug($"failed to get project info:{project.FilePath}"); + } + + var projectReference = new ProjectReference(referencedProject.Id, aliases); if (existingProjectReferences.Remove(projectReference)) { @@ -659,7 +676,7 @@ private void UpdateReferences(Project project, ImmutableArray projectRef { if (_projectFiles.TryGetValue(project.FilePath, out var projectFileInfo)) { - if (projectFileInfo.ReferenceAliases != null && projectFileInfo.ReferenceAliases.TryGetValue(referencePath, out var aliases)) + if (projectFileInfo.ReferenceAliases.TryGetValue(referencePath, out var aliases)) { if (!string.IsNullOrEmpty(aliases)) { diff --git a/test-assets/test-projects/ExternAlias/ExternAlias.App/ExternAlias.App.csproj b/test-assets/test-projects/ExternAlias/ExternAlias.App/ExternAlias.App.csproj index f2bf085d0a..b451149038 100644 --- a/test-assets/test-projects/ExternAlias/ExternAlias.App/ExternAlias.App.csproj +++ b/test-assets/test-projects/ExternAlias/ExternAlias.App/ExternAlias.App.csproj @@ -5,10 +5,6 @@ netcoreapp2.1 - - - false - $(ProjectDir)../ExternAlias.Lib/bin/$(Configuration)/netstandard2.0/ExternAlias.Lib.dll abc diff --git a/test-assets/test-projects/ExternAlias/ExternAlias.App2/ExternAlias.App2.csproj b/test-assets/test-projects/ExternAlias/ExternAlias.App2/ExternAlias.App2.csproj new file mode 100644 index 0000000000..f13ca7f132 --- /dev/null +++ b/test-assets/test-projects/ExternAlias/ExternAlias.App2/ExternAlias.App2.csproj @@ -0,0 +1,15 @@ + + + + Exe + netcoreapp2.1 + ExternAlias.App + + + + + abc + + + + diff --git a/test-assets/test-projects/ExternAlias/ExternAlias.App2/Program.cs b/test-assets/test-projects/ExternAlias/ExternAlias.App2/Program.cs new file mode 100644 index 0000000000..3364a344bd --- /dev/null +++ b/test-assets/test-projects/ExternAlias/ExternAlias.App2/Program.cs @@ -0,0 +1,14 @@ +extern alias abc; +using System; + +namespace ExternAlias.App +{ + class Program + { + static void Main(string[] args) + { + new abc::ExternAlias.Lib.Class1(); + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test-assets/test-projects/ExternAlias/ExternAlias.sln b/test-assets/test-projects/ExternAlias/ExternAlias.sln index 91117aba9a..9cac8767c2 100644 --- a/test-assets/test-projects/ExternAlias/ExternAlias.sln +++ b/test-assets/test-projects/ExternAlias/ExternAlias.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExternAlias.App", "ExternAl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExternAlias.Lib", "ExternAlias.Lib\ExternAlias.Lib.csproj", "{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExternAlias.App2", "ExternAlias.App2\ExternAlias.App2.csproj", "{220989D8-7529-4F49-BD49-8A256E6BC020}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,5 +46,17 @@ Global {ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x64.Build.0 = Release|Any CPU {ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x86.ActiveCfg = Release|Any CPU {ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x86.Build.0 = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|Any CPU.Build.0 = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|x64.ActiveCfg = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|x64.Build.0 = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|x86.ActiveCfg = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Debug|x86.Build.0 = Debug|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|Any CPU.ActiveCfg = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|Any CPU.Build.0 = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|x64.ActiveCfg = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|x64.Build.0 = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|x86.ActiveCfg = Release|Any CPU + {220989D8-7529-4F49-BD49-8A256E6BC020}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/tests/OmniSharp.MSBuild.Tests/ProjectFileInfoTests.cs b/tests/OmniSharp.MSBuild.Tests/ProjectFileInfoTests.cs index 46e10745e3..4a3b544ecf 100644 --- a/tests/OmniSharp.MSBuild.Tests/ProjectFileInfoTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/ProjectFileInfoTests.cs @@ -142,7 +142,7 @@ public async Task CSharp8AndNullableContext_has_correct_property_values() } [Fact] - public async Task ExternAlias() + public async Task ExternAliasWithReference() { using (var host = CreateOmniSharpHost()) using (var testProject = await _testAssets.GetTestProjectAsync("ExternAlias")) @@ -152,15 +152,35 @@ public async Task ExternAlias() Assert.Single(projectFileInfo.ReferenceAliases); foreach(var kv in projectFileInfo.ReferenceAliases) { - this.TestOutput.WriteLine($"{kv.Key} = {kv.Value}"); + TestOutput.WriteLine($"{kv.Key} = {kv.Value}"); } - // reference path should be same as evaluated HintPath("$(ProjectDir)../ExternAlias.Lib/bin/Debug/netstandard2.0/ExternAlias.Lib.dll") - var libpath = string.Format($"{Path.Combine(testProject.Directory, "ExternAlias.App")}{Path.DirectorySeparatorChar}../ExternAlias.Lib/bin/Debug/netstandard2.0/ExternAlias.Lib.dll"); + + var libpath = Path.Combine(testProject.Directory, "ExternAlias.Lib", "bin", "Debug", "netstandard2.0", "ExternAlias.Lib.dll"); Assert.True(projectFileInfo.ReferenceAliases.ContainsKey(libpath)); Assert.Equal("abc", projectFileInfo.ReferenceAliases[libpath]); } } + [Fact] + public async Task ExternAliasWithProjectReference() + { + using (var host = CreateOmniSharpHost()) + using (var testProject = await _testAssets.GetTestProjectAsync("ExternAlias")) + { + var projectFilePath = Path.Combine(testProject.Directory, "ExternAlias.App2", "ExternAlias.App2.csproj"); + var projectFileInfo = CreateProjectFileInfo(host, testProject, projectFilePath); + Assert.Single(projectFileInfo.ProjectReferenceAliases); + foreach(var kv in projectFileInfo.ProjectReferenceAliases) + { + TestOutput.WriteLine($"{kv.Key} = {kv.Value}"); + } + + var projectReferencePath = Path.Combine(testProject.Directory, "ExternAlias.Lib", "ExternAlias.Lib.csproj"); + Assert.True(projectFileInfo.ProjectReferenceAliases.ContainsKey(projectReferencePath)); + Assert.Equal("abc", projectFileInfo.ProjectReferenceAliases[projectReferencePath]); + } + } + [Fact] public async Task AllowUnsafe() { From 5ecc059ff3cdce7e3a161170b3bd41ccebd806c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 10 Feb 2020 22:40:23 +0200 Subject: [PATCH 2/2] Add tests to verify that aliases are added correctly to workspace. --- .../WorkspaceInformationTests.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs index 349a9d98e5..5cbb1af416 100644 --- a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging; using TestUtility; using Xunit; @@ -272,5 +273,51 @@ public async Task DoesntParticipateInWorkspaceInfoResponseWhenDisabled() Assert.Null(workspaceInfo); } } + + [Fact] + public async Task TestProjectWithAliasOnProjectReference() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ExternAlias")) + using (var host = CreateMSBuildTestHost(testProject.Directory)) + { + var project = host + .Workspace + .CurrentSolution + .Projects + .Single(x => x.AssemblyName == "ExternAlias.App2"); + + var lib = host + .Workspace + .CurrentSolution + .Projects + .Single(x => x.AssemblyName == "ExternAlias.Lib"); + + var projectReference = project + .ProjectReferences + .Single(x => x.ProjectId == lib.Id); + + Assert.Equal("abc", projectReference.Aliases.Single()); + } + } + + [Fact] + public async Task TestProjectWithAliasOnReference() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ExternAlias")) + using (var host = CreateMSBuildTestHost(testProject.Directory)) + { + var project = host + .Workspace + .CurrentSolution + .Projects + .Single(x => x.AssemblyName == "ExternAlias.App"); + + var reference = project + .MetadataReferences + .Single(x => x.Display == "ExternAlias.Lib.dll"); + + Assert.Equal("abc", reference.Properties.Aliases.Single()); + } + } } }