提交 d13df351 编写于 作者: J Jason Malinowski 提交者: GitHub

Merge pull request #13967 from mavasani/CPS_ContainedDocument

Allow ContainedDocument to be created for CPS project hierarchy
......@@ -19,11 +19,13 @@
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.EditAndContinue;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
......@@ -1443,5 +1445,91 @@ protected static bool FilterException(Exception e)
// Nothing fancy, so don't catch
return false;
}
#region FolderNames
private readonly List<string> _tmpFolders = new List<string>();
private readonly Dictionary<uint, IReadOnlyList<string>> _folderNameMap = new Dictionary<uint, IReadOnlyList<string>>();
public IReadOnlyList<string> GetFolderNamesFromHierarchy(uint documentItemID)
{
object parentObj;
if (documentItemID != (uint)VSConstants.VSITEMID.Nil && Hierarchy.GetProperty(documentItemID, (int)VsHierarchyPropID.Parent, out parentObj) == VSConstants.S_OK)
{
var parentID = UnboxVSItemId(parentObj);
if (parentID != (uint)VSConstants.VSITEMID.Nil && parentID != (uint)VSConstants.VSITEMID.Root)
{
return GetFolderNamesForFolder(parentID);
}
}
return SpecializedCollections.EmptyReadOnlyList<string>();
}
private IReadOnlyList<string> GetFolderNamesForFolder(uint folderItemID)
{
// note: use of tmpFolders is assuming this API is called on UI thread only.
_tmpFolders.Clear();
IReadOnlyList<string> names;
if (!_folderNameMap.TryGetValue(folderItemID, out names))
{
ComputeFolderNames(folderItemID, _tmpFolders, Hierarchy);
names = _tmpFolders.ToImmutableArray();
_folderNameMap.Add(folderItemID, names);
}
else
{
// verify names, and change map if we get a different set.
// this is necessary because we only get document adds/removes from the project system
// when a document name or folder name changes.
ComputeFolderNames(folderItemID, _tmpFolders, Hierarchy);
if (!Enumerable.SequenceEqual(names, _tmpFolders))
{
names = _tmpFolders.ToImmutableArray();
_folderNameMap[folderItemID] = names;
}
}
return names;
}
// Different hierarchies are inconsistent on whether they return ints or uints for VSItemIds.
// Technically it should be a uint. However, there's no enforcement of this, and marshalling
// from native to managed can end up resulting in boxed ints instead. Handle both here so
// we're resilient to however the IVsHierarchy was actually implemented.
private static uint UnboxVSItemId(object id)
{
return id is uint ? (uint)id : unchecked((uint)(int)id);
}
private static void ComputeFolderNames(uint folderItemID, List<string> names, IVsHierarchy hierarchy)
{
object nameObj;
if (hierarchy.GetProperty((uint)folderItemID, (int)VsHierarchyPropID.Name, out nameObj) == VSConstants.S_OK)
{
// For 'Shared' projects, IVSHierarchy returns a hierarchy item with < character in its name (i.e. <SharedProjectName>)
// as a child of the root item. There is no such item in the 'visual' hierarchy in solution explorer and no such folder
// is present on disk either. Since this is not a real 'folder', we exclude it from the contents of Document.Folders.
// Note: The parent of the hierarchy item that contains < character in its name is VSITEMID.Root. So we don't need to
// worry about accidental propagation out of the Shared project to any containing 'Solution' folders - the check for
// VSITEMID.Root below already takes care of that.
var name = (string)nameObj;
if (!name.StartsWith("<", StringComparison.OrdinalIgnoreCase))
{
names.Insert(0, name);
}
}
object parentObj;
if (hierarchy.GetProperty((uint)folderItemID, (int)VsHierarchyPropID.Parent, out parentObj) == VSConstants.S_OK)
{
var parentID = UnboxVSItemId(parentObj);
if (parentID != (uint)VSConstants.VSITEMID.Nil && parentID != (uint)VSConstants.VSITEMID.Root)
{
ComputeFolderNames(parentID, names, hierarchy);
}
}
}
#endregion
}
}
......@@ -2,14 +2,12 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using Roslyn.Utilities;
......@@ -71,7 +69,7 @@ public override void Disconnect()
protected void AddFile(string filename, SourceCodeKind sourceCodeKind)
{
Func<IVisualStudioHostDocument, bool> getIsCurrentContext = document => LinkedFileUtilities.IsCurrentContextHierarchy(document, RunningDocumentTable);
AddFile(filename, sourceCodeKind, getIsCurrentContext, GetFolderNames);
AddFile(filename, sourceCodeKind, getIsCurrentContext, GetFolderNamesFromHierarchy);
}
protected void SetOutputPathAndRelatedData(string objOutputPath)
......@@ -273,89 +271,5 @@ private void ValidateReferencesCore()
Contract.Requires(Debug_VBEmbeddedCoreOptionOn);
#endif
}
private readonly List<string> _tmpFolders = new List<string>();
private readonly Dictionary<uint, IReadOnlyList<string>> _folderNameMap = new Dictionary<uint, IReadOnlyList<string>>();
public IReadOnlyList<string> GetFolderNames(uint documentItemID)
{
object parentObj;
if (documentItemID != (uint)VSConstants.VSITEMID.Nil && Hierarchy.GetProperty(documentItemID, (int)VsHierarchyPropID.Parent, out parentObj) == VSConstants.S_OK)
{
var parentID = UnboxVSItemId(parentObj);
if (parentID != (uint)VSConstants.VSITEMID.Nil && parentID != (uint)VSConstants.VSITEMID.Root)
{
return GetFolderNamesForFolder(parentID);
}
}
return SpecializedCollections.EmptyReadOnlyList<string>();
}
private IReadOnlyList<string> GetFolderNamesForFolder(uint folderItemID)
{
// note: use of tmpFolders is assuming this API is called on UI thread only.
_tmpFolders.Clear();
IReadOnlyList<string> names;
if (!_folderNameMap.TryGetValue(folderItemID, out names))
{
ComputeFolderNames(folderItemID, _tmpFolders, Hierarchy);
names = _tmpFolders.ToImmutableArray();
_folderNameMap.Add(folderItemID, names);
}
else
{
// verify names, and change map if we get a different set.
// this is necessary because we only get document adds/removes from the project system
// when a document name or folder name changes.
ComputeFolderNames(folderItemID, _tmpFolders, Hierarchy);
if (!Enumerable.SequenceEqual(names, _tmpFolders))
{
names = _tmpFolders.ToImmutableArray();
_folderNameMap[folderItemID] = names;
}
}
return names;
}
// Different hierarchies are inconsistent on whether they return ints or uints for VSItemIds.
// Technically it should be a uint. However, there's no enforcement of this, and marshalling
// from native to managed can end up resulting in boxed ints instead. Handle both here so
// we're resilient to however the IVsHierarchy was actually implemented.
private static uint UnboxVSItemId(object id)
{
return id is uint ? (uint)id : unchecked((uint)(int)id);
}
private static void ComputeFolderNames(uint folderItemID, List<string> names, IVsHierarchy hierarchy)
{
object nameObj;
if (hierarchy.GetProperty((uint)folderItemID, (int)VsHierarchyPropID.Name, out nameObj) == VSConstants.S_OK)
{
// For 'Shared' projects, IVSHierarchy returns a hierarchy item with < character in its name (i.e. <SharedProjectName>)
// as a child of the root item. There is no such item in the 'visual' hierarchy in solution explorer and no such folder
// is present on disk either. Since this is not a real 'folder', we exclude it from the contents of Document.Folders.
// Note: The parent of the hierarchy item that contains < character in its name is VSITEMID.Root. So we don't need to
// worry about accidental propagation out of the Shared project to any containing 'Solution' folders - the check for
// VSITEMID.Root below already takes care of that.
var name = (string)nameObj;
if (!name.StartsWith("<", StringComparison.OrdinalIgnoreCase))
{
names.Insert(0, name);
}
}
object parentObj;
if (hierarchy.GetProperty((uint)folderItemID, (int)VsHierarchyPropID.Parent, out parentObj) == VSConstants.S_OK)
{
var parentID = UnboxVSItemId(parentObj);
if (parentID != (uint)VSConstants.VSITEMID.Nil && parentID != (uint)VSConstants.VSITEMID.Root)
{
ComputeFolderNames(parentID, names, hierarchy);
}
}
}
}
}
......@@ -20,9 +20,6 @@
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Differencing;
......@@ -90,7 +87,6 @@ internal sealed class ContainedDocument : ForegroundThreadAffinitizedObject, IVi
IFormattingRule vbHelperFormattingRule)
{
Contract.ThrowIfNull(containedLanguage);
Contract.ThrowIfFalse(containedLanguage.Project is AbstractLegacyProject);
_containedLanguage = containedLanguage;
_sourceCodeKind = sourceCodeKind;
......@@ -119,7 +115,7 @@ internal sealed class ContainedDocument : ForegroundThreadAffinitizedObject, IVi
this.Key = new DocumentKey(Project, filePath);
this.Id = DocumentId.CreateNewId(Project.Id, filePath);
this.Folders = ((AbstractLegacyProject)containedLanguage.Project).GetFolderNames(itemId);
this.Folders = containedLanguage.Project.GetFolderNamesFromHierarchy(itemId);
this.Loader = TextLoader.From(containedLanguage.SubjectBuffer.AsTextContainer(), VersionStamp.Create(), filePath);
_differenceSelectorService = componentModel.GetService<ITextDifferencingSelectorService>();
_snapshotTracker = new ReiteratedVersionSnapshotTracker(_containedLanguage.SubjectBuffer);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册