private ProjectId GetActiveContextProjectIdAndWatchHierarchies(string moniker, IEnumerable <ProjectId> projectIds, IVsHierarchy hierarchy) { _foregroundAffinitization.AssertIsForeground(); // First clear off any existing IVsHierarchies we are watching. Any ones that still matter we will resubscribe to. // We could be fancy and diff, but the cost is probably negligible. UnsubscribeFromWatchedHierarchies(moniker); if (hierarchy == null) { // Any item in the RDT should have a hierarchy associated; in this case we don't so there's absolutely nothing // we can do at this point. return(projectIds.First()); } void WatchHierarchy(IVsHierarchy hierarchyToWatch) { _watchedHierarchiesForDocumentMoniker.Add(moniker, _hierarchyEventSinkCache.GetOrCreate(hierarchyToWatch, h => new HierarchyEventSink(h, this))); } // Take a snapshot of the immutable data structure here to avoid mutation underneath us var projectToHierarchyMap = _workspace._projectToHierarchyMap; var solution = _workspace.CurrentSolution; // We now must chase to the actual hierarchy that we know about. First, we'll chase through multiple shared asset projects if // we need to do so. while (true) { var contextHierarchy = hierarchy.GetActiveProjectContext(); // The check for if contextHierarchy == hierarchy is working around downstream impacts of https://devdiv.visualstudio.com/DevDiv/_git/CPS/pullrequest/158271 // Since that bug means shared projects have themselves as their own owner, it sometimes results in us corrupting state where we end up // having the context of shared project be itself, it seems. if (contextHierarchy == null || contextHierarchy == hierarchy) { break; } WatchHierarchy(hierarchy); hierarchy = contextHierarchy; } // We may have multiple projects with the same hierarchy, but we can use __VSHPROPID8.VSHPROPID_ActiveIntellisenseProjectContext to distinguish if (ErrorHandler.Succeeded(hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID8.VSHPROPID_ActiveIntellisenseProjectContext, out var contextProjectNameObject))) { WatchHierarchy(hierarchy); if (contextProjectNameObject is string contextProjectName) { var project = _workspace.GetProjectWithHierarchyAndName(hierarchy, contextProjectName); if (project != null && projectIds.Contains(project.Id)) { return(project.Id); } } } // At this point, we should hopefully have only one project that maches by hierarchy. If there's multiple, at this point we can't figure anything // out better. var matchingProjectId = projectIds.FirstOrDefault(id => projectToHierarchyMap.GetValueOrDefault(id, null) == hierarchy); if (matchingProjectId != null) { return(matchingProjectId); } // If we had some trouble finding the project, we'll just pick one arbitrarily return(projectIds.First()); }