Skip to content

Commit 7e062c6

Browse files
authored
Merge pull request #1956 from jasonmalinowski/fix-handling-of-projectreferences
Correctly handle <ProjectReferences> that don't produce references
2 parents 942ad0b + 1c487ea commit 7e062c6

File tree

9 files changed

+125
-33
lines changed

9 files changed

+125
-33
lines changed

src/OmniSharp.MSBuild/ProjectFile/MetadataNames.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ internal static class MetadataNames
55
public const string FullPath = nameof(FullPath);
66
public const string IsImplicitlyDefined = nameof(IsImplicitlyDefined);
77
public const string Project = nameof(Project);
8-
public const string OriginalItemSpec = nameof(OriginalItemSpec);
8+
public const string ProjectReferenceOriginalItemSpec = nameof(ProjectReferenceOriginalItemSpec);
99
public const string ReferenceSourceTarget = nameof(ReferenceSourceTarget);
1010
public const string Version = nameof(Version);
1111
public const string Aliases = nameof(Aliases);

src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.ProjectData.cs

+19-30
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ public static ProjectData Create(MSB.Evaluation.Project project)
240240
documentationFile, preprocessorSymbolNames, suppressedDiagnosticIds, warningsAsErrors, warningsNotAsErrors, signAssembly, assemblyOriginatorKeyFile, treatWarningsAsErrors, defaultNamespace, runAnalyzers, runAnalyzersDuringLiveAnalysis, ruleset: null);
241241
}
242242

243-
public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance, MSB.Evaluation.Project project)
243+
public static ProjectData Create(string projectFilePath, MSB.Execution.ProjectInstance projectInstance, MSB.Evaluation.Project project)
244244
{
245+
var projectFolderPath = Path.GetDirectoryName(projectFilePath);
246+
245247
var guid = PropertyConverter.ToGuid(projectInstance.GetPropertyValue(PropertyNames.ProjectGuid));
246248
var name = projectInstance.GetPropertyValue(PropertyNames.ProjectName);
247249
var assemblyName = projectInstance.GetPropertyValue(PropertyNames.AssemblyName);
@@ -286,41 +288,32 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance,
286288

287289
var projectReferences = ImmutableArray.CreateBuilder<string>();
288290
var projectReferenceAliases = ImmutableDictionary.CreateBuilder<string, string>();
289-
var projectReferencesAdded = new HashSet<string>();
290-
foreach (var projectReferenceItem in projectInstance.GetItems(ItemNames.ProjectReference))
291-
{
292-
var fullPath = projectReferenceItem.GetMetadataValue(MetadataNames.FullPath);
293-
294-
if (IsCSharpProject(fullPath) && projectReferencesAdded.Add(fullPath))
295-
{
296-
projectReferences.Add(fullPath);
297-
298-
var aliases = projectReferenceItem.GetMetadataValue(MetadataNames.Aliases);
299-
if (!string.IsNullOrEmpty(aliases))
300-
{
301-
projectReferenceAliases[fullPath] = aliases;
302-
}
303-
}
304-
}
305291

306292
var references = ImmutableArray.CreateBuilder<string>();
307293
var referenceAliases = ImmutableDictionary.CreateBuilder<string, string>();
308294
foreach (var referencePathItem in projectInstance.GetItems(ItemNames.ReferencePath))
309295
{
310296
var referenceSourceTarget = referencePathItem.GetMetadataValue(MetadataNames.ReferenceSourceTarget);
297+
var aliases = referencePathItem.GetMetadataValue(MetadataNames.Aliases);
311298

299+
// If this reference came from a project reference, count it as such. We never want to directly look
300+
// at the ProjectReference items in the project, as those don't always create project references
301+
// if things like OutputItemType or ReferenceOutputAssembly are set. It's also possible that other
302+
// MSBuild logic is adding or removing properties too.
312303
if (StringComparer.OrdinalIgnoreCase.Equals(referenceSourceTarget, ItemNames.ProjectReference))
313304
{
314-
// If the reference was sourced from a project reference, we have two choices:
315-
//
316-
// 1. If the reference is a C# project reference, we shouldn't add it because it'll just duplicate
317-
// the project reference.
318-
// 2. If the reference is *not* a C# project reference, we should keep this reference because the
319-
// project reference was already removed.
320-
321-
var originalItemSpec = referencePathItem.GetMetadataValue(MetadataNames.OriginalItemSpec);
322-
if (originalItemSpec.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
305+
var projectReferenceOriginalItemSpec = referencePathItem.GetMetadataValue(MetadataNames.ProjectReferenceOriginalItemSpec);
306+
if (projectReferenceOriginalItemSpec.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
323307
{
308+
var projectReferenceFilePath = Path.GetFullPath(Path.Combine(projectFolderPath, projectReferenceOriginalItemSpec));
309+
310+
projectReferences.Add(projectReferenceFilePath);
311+
312+
if (!string.IsNullOrEmpty(aliases))
313+
{
314+
projectReferenceAliases[projectReferenceFilePath] = aliases;
315+
}
316+
324317
continue;
325318
}
326319
}
@@ -330,7 +323,6 @@ public static ProjectData Create(MSB.Execution.ProjectInstance projectInstance,
330323
{
331324
references.Add(fullPath);
332325

333-
var aliases = referencePathItem.GetMetadataValue(MetadataNames.Aliases);
334326
if (!string.IsNullOrEmpty(aliases))
335327
{
336328
referenceAliases[fullPath] = aliases;
@@ -395,9 +387,6 @@ private static RuleSet ResolveRulesetIfAny(MSB.Execution.ProjectInstance project
395387
return null;
396388
}
397389

398-
private static bool IsCSharpProject(string filePath)
399-
=> filePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase);
400-
401390
private static bool FileNameIsNotGenerated(string filePath)
402391
=> !Path.GetFileName(filePath).StartsWith("TemporaryGeneratedFile_", StringComparison.OrdinalIgnoreCase);
403392

src/OmniSharp.MSBuild/ProjectFile/ProjectFileInfo.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public static (ProjectFileInfo, ImmutableArray<MSBuildDiagnostic>, ProjectLoaded
119119
return (null, diagnostics, null);
120120
}
121121

122-
var data = ProjectData.Create(projectInstance, project);
122+
var data = ProjectData.Create(filePath, projectInstance, project);
123123
var projectFileInfo = new ProjectFileInfo(projectIdInfo, filePath, data, sessionId, dotNetInfo);
124124
var eventArgs = new ProjectLoadedEventArgs(projectIdInfo.Id,
125125
project,
@@ -143,7 +143,7 @@ public static (ProjectFileInfo, ImmutableArray<MSBuildDiagnostic>, ProjectLoaded
143143
return (null, diagnostics, null);
144144
}
145145

146-
var data = ProjectData.Create(projectInstance, project);
146+
var data = ProjectData.Create(FilePath, projectInstance, project);
147147
var projectFileInfo = new ProjectFileInfo(ProjectIdInfo, FilePath, data, SessionId, DotNetInfo);
148148
var eventArgs = new ProjectLoadedEventArgs(Id,
149149
project,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System;
2+
3+
namespace Analyzer
4+
{
5+
public class Class1
6+
{
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.1</TargetFramework>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<ProjectReference Include="..\Analyzer\Analyzer.csproj">
9+
<OutputItemType>Analyzer</OutputItemType>
10+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
11+
</ProjectReference>
12+
</ItemGroup>
13+
14+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace ConsumingProject.App
4+
{
5+
class Program
6+
{
7+
static void Main(string[] args)
8+
{
9+
Console.WriteLine("Hello World!");
10+
}
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26124.0
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Analyzer", "Analyzer\Analyzer.csproj", "{447E6D15-63B0-47F3-9E44-D6F0D0087C46}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumingProject", "ConsumingProject\ConsumingProject.csproj", "{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Debug|x64 = Debug|x64
14+
Debug|x86 = Debug|x86
15+
Release|Any CPU = Release|Any CPU
16+
Release|x64 = Release|x64
17+
Release|x86 = Release|x86
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
23+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|Any CPU.Build.0 = Debug|Any CPU
25+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|x64.ActiveCfg = Debug|Any CPU
26+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|x64.Build.0 = Debug|Any CPU
27+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|x86.ActiveCfg = Debug|Any CPU
28+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Debug|x86.Build.0 = Debug|Any CPU
29+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|Any CPU.ActiveCfg = Release|Any CPU
30+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|Any CPU.Build.0 = Release|Any CPU
31+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|x64.ActiveCfg = Release|Any CPU
32+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|x64.Build.0 = Release|Any CPU
33+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|x86.ActiveCfg = Release|Any CPU
34+
{447E6D15-63B0-47F3-9E44-D6F0D0087C46}.Release|x86.Build.0 = Release|Any CPU
35+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|Any CPU.Build.0 = Debug|Any CPU
37+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|x64.ActiveCfg = Debug|Any CPU
38+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|x64.Build.0 = Debug|Any CPU
39+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|x86.ActiveCfg = Debug|Any CPU
40+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Debug|x86.Build.0 = Debug|Any CPU
41+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|Any CPU.ActiveCfg = Release|Any CPU
42+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|Any CPU.Build.0 = Release|Any CPU
43+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x64.ActiveCfg = Release|Any CPU
44+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x64.Build.0 = Release|Any CPU
45+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x86.ActiveCfg = Release|Any CPU
46+
{ECC29DFA-3AC0-474E-9C5C-C8AD4D3DD17D}.Release|x86.Build.0 = Release|Any CPU
47+
EndGlobalSection
48+
EndGlobal

tests/OmniSharp.MSBuild.Tests/ProjectFileInfoTests.cs

+14
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,19 @@ public async Task WarningsAsErrors()
229229
Assert.Equal(ReportDiagnostic.Suppress, compilationOptions.SpecificDiagnosticOptions["CS7081"]);
230230
}
231231
}
232+
233+
[Fact]
234+
public async Task ProjectReferenceProducingAnalyzerItems()
235+
{
236+
using (var host = CreateOmniSharpHost())
237+
using (var testProject = await _testAssets.GetTestProjectAsync("ProjectWithAnalyzersFromReference"))
238+
{
239+
var projectFilePath = Path.Combine(testProject.Directory, "ConsumingProject", "ConsumingProject.csproj");
240+
var projectFileInfo = CreateProjectFileInfo(host, testProject, projectFilePath);
241+
Assert.Empty(projectFileInfo.ProjectReferences);
242+
var analyzerFileReference = Assert.Single(projectFileInfo.Analyzers);
243+
Assert.EndsWith("Analyzer.dll", analyzerFileReference);
244+
}
245+
}
232246
}
233247
}

0 commit comments

Comments
 (0)