diff --git a/build.json b/build.json index 0fcd698eb2..a1d6ee9d54 100644 --- a/build.json +++ b/build.json @@ -35,7 +35,8 @@ "ProjectAndSolution", "ProjectAndSolutionWithProjectSection", "TwoProjectsWithSolution", - "ProjectWithGeneratedFile" + "ProjectWithGeneratedFile", + "CSharpAndFSharp" ], "LegacyTestAssets": [ "LegacyNUnitTestProject", diff --git a/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs b/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs index dfe07e6f05..6f9ba7e17f 100644 --- a/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs +++ b/src/OmniSharp.MSBuild/MSBuildProjectSystem.cs @@ -465,7 +465,8 @@ private void UpdateProjectReferences(Project project, ImmutableArray pro { if (!_projects.TryGetValue(projectReferencePath, out var referencedProject)) { - if (File.Exists(projectReferencePath)) + if (File.Exists(projectReferencePath) && + projectReferencePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) { _logger.LogInformation($"Found referenced project outside root directory: {projectReferencePath}"); diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.MetadataNames.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.MetadataNames.cs index 508e05ee4f..98602345a9 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.MetadataNames.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.MetadataNames.cs @@ -7,6 +7,7 @@ private static class MetadataNames public const string FullPath = nameof(FullPath); public const string IsImplicitlyDefined = nameof(IsImplicitlyDefined); public const string Project = nameof(Project); + public const string OriginalItemSpec = nameof(OriginalItemSpec); public const string ReferenceSourceTarget = nameof(ReferenceSourceTarget); public const string Version = nameof(Version); } diff --git a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs index 5e24def329..44dc067a2b 100644 --- a/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs +++ b/src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs @@ -205,9 +205,38 @@ private static ProjectData CreateProjectData(ProjectInstance projectInstance, Im var sourceFiles = GetFullPaths( projectInstance.GetItems(ItemNames.Compile), filter: FileNameIsNotGenerated); - var projectReferences = GetFullPaths(projectInstance.GetItems(ItemNames.ProjectReference)); - var references = GetFullPaths( - projectInstance.GetItems(ItemNames.ReferencePath).Where(ReferenceSourceTargetIsNotProjectReference)); + + var projectReferences = GetFullPaths( + projectInstance.GetItems(ItemNames.ProjectReference), filter: IsCSharpProject); + + var references = ImmutableArray.CreateBuilder(); + foreach (var referencePathItem in projectInstance.GetItems(ItemNames.ReferencePath)) + { + var referenceSourceTarget = referencePathItem.GetMetadataValue(MetadataNames.ReferenceSourceTarget); + + if (StringComparer.OrdinalIgnoreCase.Equals(referenceSourceTarget, ItemNames.ProjectReference)) + { + // If the reference was sourced from a project reference, we have two choices: + // + // 1. If the reference is a C# project reference, we shouldn't add it because it'll just duplicate + // the project reference. + // 2. If the reference is *not* a C# project reference, we should keep this reference because the + // project reference was already removed. + + var originalItemSpec = referencePathItem.GetMetadataValue(MetadataNames.OriginalItemSpec); + if (originalItemSpec.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + } + + var fullPath = referencePathItem.GetMetadataValue(MetadataNames.FullPath); + if (!string.IsNullOrEmpty(fullPath)) + { + references.Add(fullPath); + } + } + var packageReferences = GetPackageReferences(projectInstance.GetItems(ItemNames.PackageReference)); var analyzers = GetFullPaths(projectInstance.GetItems(ItemNames.Analyzer)); @@ -216,7 +245,7 @@ private static ProjectData CreateProjectData(ProjectInstance projectInstance, Im targetFramework, targetFrameworks, outputKind, languageVersion, allowUnsafeCode, documentationFile, preprocessorSymbolNames, suppressDiagnosticIds, signAssembly, assemblyOriginatorKeyFile, - sourceFiles, projectReferences, references, packageReferences, analyzers); + sourceFiles, projectReferences, references.ToImmutable(), packageReferences, analyzers); } public ProjectFileInfo Reload( @@ -273,11 +302,11 @@ private static Dictionary GetGlobalProperties(MSBuildInstance ms return globalProperties; } - private static bool ReferenceSourceTargetIsNotProjectReference(ProjectItemInstance item) - => item.GetMetadataValue(MetadataNames.ReferenceSourceTarget) != ItemNames.ProjectReference; + private static bool IsCSharpProject(string filePath) + => filePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase); private static bool FileNameIsNotGenerated(string filePath) - => !Path.GetFileName(filePath).StartsWith("TemporaryGeneratedFile_"); + => !Path.GetFileName(filePath).StartsWith("TemporaryGeneratedFile_", StringComparison.OrdinalIgnoreCase); private static ImmutableArray GetFullPaths(IEnumerable items, Func filter = null) { diff --git a/test-assets/test-projects/CSharpAndFSharp/CSharpAndFSharp.sln b/test-assets/test-projects/CSharpAndFSharp/CSharpAndFSharp.sln new file mode 100644 index 0000000000..d4cf949602 --- /dev/null +++ b/test-assets/test-projects/CSharpAndFSharp/CSharpAndFSharp.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp-console", "csharp-console\csharp-console.csproj", "{ED247A90-AFBE-4717-8F32-AA8BFC2C8627}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "fsharp-lib", "fsharp-lib\fsharp-lib.fsproj", "{4FCFD6A3-2860-42C4-B98E-ADAEC268B928}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|x64.ActiveCfg = Debug|x64 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|x64.Build.0 = Debug|x64 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|x86.ActiveCfg = Debug|x86 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Debug|x86.Build.0 = Debug|x86 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|Any CPU.Build.0 = Release|Any CPU + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|x64.ActiveCfg = Release|x64 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|x64.Build.0 = Release|x64 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|x86.ActiveCfg = Release|x86 + {ED247A90-AFBE-4717-8F32-AA8BFC2C8627}.Release|x86.Build.0 = Release|x86 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|x64.ActiveCfg = Debug|x64 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|x64.Build.0 = Debug|x64 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|x86.ActiveCfg = Debug|x86 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Debug|x86.Build.0 = Debug|x86 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|Any CPU.Build.0 = Release|Any CPU + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|x64.ActiveCfg = Release|x64 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|x64.Build.0 = Release|x64 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|x86.ActiveCfg = Release|x86 + {4FCFD6A3-2860-42C4-B98E-ADAEC268B928}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/test-assets/test-projects/CSharpAndFSharp/csharp-console/Program.cs b/test-assets/test-projects/CSharpAndFSharp/csharp-console/Program.cs new file mode 100644 index 0000000000..1ebeafa81a --- /dev/null +++ b/test-assets/test-projects/CSharpAndFSharp/csharp-console/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace csharp_console +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test-assets/test-projects/CSharpAndFSharp/csharp-console/csharp-console.csproj b/test-assets/test-projects/CSharpAndFSharp/csharp-console/csharp-console.csproj new file mode 100644 index 0000000000..af64f07386 --- /dev/null +++ b/test-assets/test-projects/CSharpAndFSharp/csharp-console/csharp-console.csproj @@ -0,0 +1,12 @@ + + + + + + + + Exe + netcoreapp2.0 + + + diff --git a/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/Library.fs b/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/Library.fs new file mode 100644 index 0000000000..f5fa3f0d9f --- /dev/null +++ b/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/Library.fs @@ -0,0 +1,5 @@ +namespace lib + +module Say = + let hello name = + printfn "Hello %s" name diff --git a/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/fsharp-lib.fsproj b/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/fsharp-lib.fsproj new file mode 100644 index 0000000000..df4543225f --- /dev/null +++ b/test-assets/test-projects/CSharpAndFSharp/fsharp-lib/fsharp-lib.fsproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs index 0be40d54ac..8b906655cb 100644 --- a/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs @@ -105,6 +105,23 @@ public async Task ProjectWithSdkProperty() } } + [Fact] + public async Task CSharpAndFSharp() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("CSharpAndFSharp")) + using (var host = CreateOmniSharpHost(testProject.Directory)) + { + var workspaceInfo = await GetWorkspaceInfoAsync(host); + + Assert.NotNull(workspaceInfo.Projects); + Assert.Equal(1, workspaceInfo.Projects.Count); + + var project = workspaceInfo.Projects[0]; + Assert.Equal("csharp-console.csproj", Path.GetFileName(project.Path)); + Assert.Equal(3, project.SourceFiles.Count); + } + } + [ConditionalFact(typeof(WindowsOnly))] public async Task AntlrGeneratedFiles() {