Skip to content

Commit 237f04c

Browse files
authored
Merge pull request #19872 from tmeschter/HandleWebApplicationProjects
Exclude projects for aspx/cshtml/vbhtml files
2 parents 8d1d7ae + d6ebdee commit 237f04c

File tree

1 file changed

+55
-40
lines changed

1 file changed

+55
-40
lines changed

src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs

+55-40
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.CodeAnalysis;
66
using Microsoft.CodeAnalysis.Host.Mef;
77
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
8+
using Microsoft.VisualStudio.LanguageServices.Implementation.Venus;
89
using Microsoft.VisualStudio.Shell;
910

1011
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
@@ -43,56 +44,70 @@ public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, string targetFramewo
4344
return false;
4445
}
4546

46-
var project = _workspace.DeferredState.ProjectTracker.ImmutableProjects
47-
.Where(p =>
47+
// First filter the projects by matching up properties on the input hierarchy against properties on each
48+
// project's hierarchy.
49+
var candidateProjects = _workspace.DeferredState.ProjectTracker.ImmutableProjects
50+
.Where(p =>
51+
{
52+
// We're about to access various properties of the IVsHierarchy associated with the project.
53+
// The properties supported and the interpretation of their values varies from one project system
54+
// to another. This code is designed with C# and VB in mind, so we need to filter out everything
55+
// else.
56+
if (p.Language != LanguageNames.CSharp
57+
&& p.Language != LanguageNames.VisualBasic)
4858
{
49-
// We're about to access various properties of the IVsHierarchy associated with the project.
50-
// The properties supported and the interpretation of their values varies from one project system
51-
// to another. This code is designed with C# and VB in mind, so we need to filter out everything
52-
// else.
53-
if (p.Language != LanguageNames.CSharp
54-
&& p.Language != LanguageNames.VisualBasic)
55-
{
56-
return false;
57-
}
59+
return false;
60+
}
5861

59-
// Here we try to match the hierarchy from Solution Explorer to a hierarchy from the Roslyn project.
60-
// The canonical name of a hierarchy item must be unique _within_ an hierarchy, but since we're
61-
// examining multiple hierarchies the canonical name could be the same. Indeed this happens when two
62-
// project files are in the same folder--they both use the full path to the _folder_ as the canonical
63-
// name. To distinguish them we also examine the "regular" name, which will necessarily be different
64-
// if the two projects are in the same folder.
65-
// Note that if a project has been loaded with Lightweight Solution Load it won't even have a
66-
// hierarchy, so we need to check for null first.
67-
if (p.Hierarchy != null
68-
&& p.Hierarchy.TryGetCanonicalName((uint)VSConstants.VSITEMID.Root, out string projectCanonicalName)
69-
&& p.Hierarchy.TryGetItemName((uint)VSConstants.VSITEMID.Root, out string projectName)
70-
&& projectCanonicalName.Equals(nestedCanonicalName, System.StringComparison.OrdinalIgnoreCase)
71-
&& projectName.Equals(nestedName))
62+
// Here we try to match the hierarchy from Solution Explorer to a hierarchy from the Roslyn project.
63+
// The canonical name of a hierarchy item must be unique _within_ an hierarchy, but since we're
64+
// examining multiple hierarchies the canonical name could be the same. Indeed this happens when two
65+
// project files are in the same folder--they both use the full path to the _folder_ as the canonical
66+
// name. To distinguish them we also examine the "regular" name, which will necessarily be different
67+
// if the two projects are in the same folder.
68+
// Note that if a project has been loaded with Lightweight Solution Load it won't even have a
69+
// hierarchy, so we need to check for null first.
70+
if (p.Hierarchy != null
71+
&& p.Hierarchy.TryGetCanonicalName((uint)VSConstants.VSITEMID.Root, out string projectCanonicalName)
72+
&& p.Hierarchy.TryGetItemName((uint)VSConstants.VSITEMID.Root, out string projectName)
73+
&& projectCanonicalName.Equals(nestedCanonicalName, System.StringComparison.OrdinalIgnoreCase)
74+
&& projectName.Equals(nestedName))
75+
{
76+
if (targetFrameworkMoniker == null)
7277
{
73-
if (targetFrameworkMoniker == null)
74-
{
75-
return true;
76-
}
77-
78-
return p.Hierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out string projectTargetFrameworkMoniker)
79-
&& projectTargetFrameworkMoniker.Equals(targetFrameworkMoniker);
78+
return true;
8079
}
8180

82-
return false;
83-
})
84-
.SingleOrDefault();
81+
return p.Hierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out string projectTargetFrameworkMoniker)
82+
&& projectTargetFrameworkMoniker.Equals(targetFrameworkMoniker);
83+
}
84+
85+
return false;
86+
})
87+
.ToArray();
8588

86-
if (project == null)
89+
// If we only have one candidate then no further checks are required.
90+
if (candidateProjects.Length == 1)
8791
{
88-
projectId = default(ProjectId);
89-
return false;
92+
projectId = candidateProjects[0].Id;
93+
return true;
9094
}
91-
else
95+
96+
// If we have multiple candidates then we might be dealing with Web Application Projects. In this case
97+
// there will be one main project plus one project for each open aspx/cshtml/vbhtml file, all with
98+
// identical properties on their hierarchies. We can find the main project by taking the first project
99+
// without a ContainedDocument.
100+
foreach (var candidateProject in candidateProjects)
92101
{
93-
projectId = project.Id;
94-
return true;
102+
if (!candidateProject.GetCurrentDocuments().Any(doc => doc is ContainedDocument))
103+
{
104+
projectId = candidateProject.Id;
105+
return true;
106+
}
95107
}
108+
109+
projectId = default(ProjectId);
110+
return false;
96111
}
97112
}
98113
}

0 commit comments

Comments
 (0)