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

Merge pull request #14016 from vslsnap/merge-dev15-preview-5-into-master20160923-150132

Merge dev15-preview-5 into master
......@@ -284,6 +284,7 @@
or '%(FileName)' == 'Microsoft.VisualStudio.Shell.Interop.12.0'
or '%(FileName)' == 'Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime'
or '%(FileName)' == 'Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime'
or '%(FileName)' == 'Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime'
or '%(Filename)' == 'Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime'
or '%(FileName)' == 'Microsoft.VisualStudio.TextManager.Interop.12.1.DesignTime'
or '%(FileName)' == 'Microsoft.Internal.VisualStudio.Shell.Interop.14.0.DesignTime'
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim;
using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.LanguageServices.ProjectSystem;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService
......@@ -16,6 +19,8 @@ internal partial class CSharpLanguageService : ICSharpProjectHost
public void BindToProject(ICSharpProjectRoot projectRoot, IVsHierarchy hierarchy)
{
var projectName = Path.GetFileName(projectRoot.GetFullProjectName()); // GetFullProjectName returns the path to the project file w/o the extension?
Workspace.ProjectTracker.TryDisconnectExistingDeferredProject(hierarchy, projectName);
var project = new CSharpProjectShimWithServices(
projectRoot,
this.Workspace.ProjectTracker,
......
......@@ -64,24 +64,7 @@ public void OnSourceFileAdded(string filename)
// ? SourceCodeKind.Script
// : SourceCodeKind.Regular;
var sourceCodeKind = SourceCodeKind.Regular;
IVsHierarchy foundHierarchy;
uint itemId;
if (ErrorHandler.Succeeded(_projectRoot.GetHierarchyAndItemID(filename, out foundHierarchy, out itemId)))
{
Debug.Assert(foundHierarchy == this.Hierarchy);
}
else
{
// Unfortunately, the project system does pass us some files which aren't part of
// the project as far as the hierarchy and itemid are concerned. We'll just used
// VSITEMID.Nil for them.
foundHierarchy = null;
itemId = (uint)VSConstants.VSITEMID.Nil;
}
AddFile(filename, sourceCodeKind, itemId);
AddFile(filename, sourceCodeKind);
}
public void OnSourceFileRemoved(string filename)
......
......@@ -46,9 +46,7 @@ public void AddRemoveProjectAndMetadataReference_CPS()
((IWorkspaceProjectContext)project4).BinOutputPath = @"C:\project4.dll";
Assert.Equal(@"C:\project4.dll", project4.BinOutputPath);
// This is currently broken by https://github.com/dotnet/roslyn/issues/12707
// Reverse the below assert to Assert.True once the above bug is fixed.
Assert.False(project3.GetCurrentProjectReferences().Any(pr => pr.ProjectId == project4.Id));
Assert.True(project3.GetCurrentProjectReferences().Any(pr => pr.ProjectId == project4.Id));
// Remove project reference
project3.RemoveProjectReference(project1);
......
......@@ -78,11 +78,9 @@ public static bool TryGetImageListAndIndex(this VisualStudioWorkspaceImpl worksp
public static bool TryGetImageListAndIndex(this VisualStudioWorkspaceImpl workspace, IVsImageService2 imageService, ProjectId id, out IntPtr imageList, out ushort index)
{
var project = workspace.GetHostProject(id);
if (project != null)
var hierarchy = workspace.GetHostProject(id)?.Hierarchy;
if (hierarchy != null)
{
var hierarchy = project.Hierarchy;
return TryGetImageListAndIndex(hierarchy, imageService, VSConstants.VSITEMID_ROOT, out imageList, out index);
}
......
......@@ -187,6 +187,9 @@ internal abstract partial class AbstractProject : ForegroundThreadAffinitizedObj
private ICommandLineParserService CommandLineParserService { get; }
/// <summary>
/// The <see cref="IVsHierarchy"/> for this project. NOTE: May be null in Deferred Project Load cases.
/// </summary>
public IVsHierarchy Hierarchy { get; }
/// <summary>
......@@ -892,15 +895,19 @@ private static void OnAdditionalDocumentUpdatedOnDisk(object sender, EventArgs e
}
}
protected void AddFile(string filename, SourceCodeKind sourceCodeKind, Func<IVisualStudioHostDocument, bool> getIsCurrentContext, IReadOnlyList<string> folderNames)
protected void AddFile(
string filename,
SourceCodeKind sourceCodeKind,
Func<IVisualStudioHostDocument, bool> getIsCurrentContext,
Func<uint, IReadOnlyList<string>> getFolderNames)
{
// We can currently be on a background thread.
// So, hookup the handlers when creating the standard text document, as we might receive these handler notifications on the UI thread.
var document = this.DocumentProvider.TryGetDocumentForFile(
this,
folderNames,
filePath: filename,
sourceCodeKind: sourceCodeKind,
getFolderNames: getFolderNames,
canUseTextBuffer: CanUseTextBuffer,
updatedOnDiskHandler: s_documentUpdatedOnDiskEventHandler,
openedHandler: s_documentOpenedEventHandler,
......
......@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
......@@ -125,9 +126,9 @@ public void AddAdditionalFile(string additionalFilePath, Func<IVisualStudioHostD
{
var document = this.DocumentProvider.TryGetDocumentForFile(
this,
ImmutableArray<string>.Empty,
filePath: additionalFilePath,
sourceCodeKind: SourceCodeKind.Regular,
getFolderNames: _ => SpecializedCollections.EmptyReadOnlyList<string>(),
canUseTextBuffer: _ => true,
updatedOnDiskHandler: s_additionalDocumentUpdatedOnDiskEventHandler,
openedHandler: s_additionalDocumentOpenedEventHandler,
......
......@@ -19,7 +19,7 @@ internal interface IWorkspaceProjectContextFactory
/// <param name="projectDisplayName">Display name for the project.</param>
/// <param name="projectFilePath">Full path to the project file for the project.</param>
/// <param name="projectGuid">Project guid.</param>
/// <param name="hierarchy"><see cref="IVsHierarchy"/> for the project.</param>
/// <param name="hierarchy"><see cref="IVsHierarchy"/> for the project, an be null in deferred project load cases.</param>
/// <param name="binOutputPath">Initial project binary output path.</param>
IWorkspaceProjectContext CreateProjectContext(string languageName, string projectDisplayName, string projectFilePath, Guid projectGuid, object hierarchy, string binOutputPath);
}
......
......@@ -45,11 +45,15 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
public event EventHandler<bool> Opened;
public event EventHandler<bool> Closing;
/// <summary>
/// Creates a <see cref="StandardTextDocument"/>.
/// <para>Note: getFolderNames maps from a VSITEMID to the folders this document should be contained in.</para>
/// </summary>
public StandardTextDocument(
DocumentProvider documentProvider,
IVisualStudioHostProject project,
DocumentKey documentKey,
IReadOnlyList<string> folderNames,
Func<uint, IReadOnlyList<string>> getFolderNames,
SourceCodeKind sourceCodeKind,
ITextUndoHistoryRegistry textUndoHistoryRegistry,
IVsFileChangeEx fileChangeService,
......@@ -63,13 +67,17 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS
this.Project = project;
this.Id = id ?? DocumentId.CreateNewId(project.Id, documentKey.Moniker);
this.Folders = folderNames;
_itemMoniker = documentKey.Moniker;
var itemid = this.GetItemId();
this.Folders = itemid == (uint)VSConstants.VSITEMID.Nil
? SpecializedCollections.EmptyReadOnlyList<string>()
: getFolderNames(itemid);
_documentProvider = documentProvider;
this.Key = documentKey;
this.SourceCodeKind = sourceCodeKind;
_itemMoniker = documentKey.Moniker;
_textUndoHistoryRegistry = textUndoHistoryRegistry;
_fileChangeTracker = new FileChangeTracker(fileChangeService, this.FilePath);
_fileChangeTracker.UpdatedOnDisk += OnUpdatedOnDisk;
......@@ -251,7 +259,7 @@ public uint GetItemId()
{
AssertIsForeground();
if (_itemMoniker == null)
if (_itemMoniker == null || Project.Hierarchy == null)
{
return (uint)VSConstants.VSITEMID.Nil;
}
......
......@@ -95,10 +95,10 @@ internal abstract partial class DocumentProvider : ForegroundThreadAffinitizedOb
/// </summary>
public IVisualStudioHostDocument TryGetDocumentForFile(
IVisualStudioHostProject hostProject,
IReadOnlyList<string> folderNames,
string filePath,
SourceCodeKind sourceCodeKind,
Func<ITextBuffer, bool> canUseTextBuffer,
Func<uint, IReadOnlyList<string>> getFolderNames,
EventHandler updatedOnDiskHandler = null,
EventHandler<bool> openedHandler = null,
EventHandler<bool> closingHandler = null)
......@@ -163,7 +163,7 @@ internal abstract partial class DocumentProvider : ForegroundThreadAffinitizedOb
this,
hostProject,
documentKey,
folderNames,
getFolderNames,
sourceCodeKind,
_textUndoHistoryRegistry,
_fileChangeService,
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal interface IDeferredProjectWorkspaceService : IWorkspaceService
{
bool IsDeferredProjectLoadEnabled { get; }
/// <summary>
/// Returns a mapping of project file path to information about that project.
/// </summary>
Task<IReadOnlyDictionary<string, DeferredProjectInformation>> GetDeferredProjectInfoForConfigurationAsync(
string solutionConfiguration,
CancellationToken cancellationToken);
}
internal struct DeferredProjectInformation
{
public DeferredProjectInformation(
string targetPath,
ImmutableArray<string> commandLineArgs,
ImmutableArray<string> referencedProjectFilePaths)
{
TargetPath = targetPath;
CommandLineArguments = commandLineArgs;
ReferencedProjectFilePaths = referencedProjectFilePaths;
}
/// <summary>
/// The full path to the binary this project would create if built *by msbuild*.
/// May be different than the /out argument in <see cref="CommandLineArguments"/>.
/// </summary>
public string TargetPath { get; }
/// <summary>
/// The set of command line arguments that can be used to build this project.
/// </summary>
public ImmutableArray<string> CommandLineArguments { get; }
/// <summary>
/// The paths to referenced projects.
/// </summary>
public ImmutableArray<string> ReferencedProjectFilePaths { get; }
}
}
......@@ -15,6 +15,9 @@ internal interface IVisualStudioHostProject
ProjectId Id { get; }
string Language { get; }
/// <summary>
/// The <see cref="IVsHierarchy"/> for this project. NOTE: May be null in Deferred Project Load cases.
/// </summary>
IVsHierarchy Hierarchy { get; }
Guid Guid { get; }
......
......@@ -45,8 +45,11 @@ internal abstract partial class AbstractLegacyProject : AbstractProject
hostDiagnosticUpdateSourceOpt: hostDiagnosticUpdateSourceOpt,
commandLineParserServiceOpt: commandLineParserServiceOpt)
{
ConnectHierarchyEvents();
this.IsWebSite = GetIsWebsiteProject(hierarchy);
if (Hierarchy != null)
{
ConnectHierarchyEvents();
this.IsWebSite = GetIsWebsiteProject(Hierarchy);
}
// Initialize command line arguments.
base.SetArguments(commandLine: string.Empty);
......@@ -65,10 +68,10 @@ public override void Disconnect()
DisconnectHierarchyEvents();
}
protected void AddFile(string filename, SourceCodeKind sourceCodeKind, uint itemId)
protected void AddFile(string filename, SourceCodeKind sourceCodeKind)
{
Func<IVisualStudioHostDocument, bool> getIsCurrentContext = document => LinkedFileUtilities.IsCurrentContextHierarchy(document, RunningDocumentTable);
AddFile(filename, sourceCodeKind, getIsCurrentContext, GetFolderNames(itemId));
AddFile(filename, sourceCodeKind, getIsCurrentContext, GetFolderNames);
}
protected void SetOutputPathAndRelatedData(string objOutputPath)
......@@ -124,7 +127,7 @@ private static string GetProjectDisplayName(IVsHierarchy hierarchy)
return hierarchy.TryGetName(out name) ? name : null;
}
private static string GetProjectFilePath(IVsHierarchy hierarchy)
internal static string GetProjectFilePath(IVsHierarchy hierarchy)
{
string filePath;
return ErrorHandler.Succeeded(((IVsProject3)hierarchy).GetMkDocument((uint)VSConstants.VSITEMID.Root, out filePath)) ? filePath : null;
......
......@@ -311,9 +311,9 @@ private void AttachToDocument(uint docCookie, string moniker)
// Now try to find the document. We accept any text buffer, since we've already verified it's an appropriate file in ShouldIncludeFile.
var document = _documentProvider.TryGetDocumentForFile(
hostProject,
ImmutableArray<string>.Empty,
moniker,
parseOptions.Kind,
getFolderNames: _ => SpecializedCollections.EmptyReadOnlyList<string>(),
canUseTextBuffer: _ => true);
// If the buffer has not yet been initialized, we won't get a document.
......
......@@ -3,13 +3,19 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy;
using Microsoft.VisualStudio.LanguageServices.ProjectSystem;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
......@@ -29,6 +35,8 @@ internal sealed partial class VisualStudioProjectTracker : ForegroundThreadAffin
#region Mutable fields accessed only from foreground thread - don't need locking for access (all accessing methods must have AssertIsForeground).
private readonly List<WorkspaceHostState> _workspaceHosts;
private readonly HostWorkspaceServices _workspaceServices;
/// <summary>
/// The list of projects loaded in this batch between <see cref="IVsSolutionLoadEvents.OnBeforeLoadProjectBatch" /> and
/// <see cref="IVsSolutionLoadEvents.OnAfterLoadProjectBatch(bool)"/>.
......@@ -100,7 +108,7 @@ void IVisualStudioHostProjectContainer.NotifyNonDocumentOpenedForProject(IVisual
StartPushingToWorkspaceAndNotifyOfOpenDocuments(SpecializedCollections.SingletonEnumerable(abstractProject));
}
public VisualStudioProjectTracker(IServiceProvider serviceProvider)
public VisualStudioProjectTracker(IServiceProvider serviceProvider, HostWorkspaceServices workspaceServices)
: base(assertIsForeground: true)
{
_projectMap = new Dictionary<ProjectId, AbstractProject>();
......@@ -108,6 +116,7 @@ public VisualStudioProjectTracker(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
_workspaceHosts = new List<WorkspaceHostState>(capacity: 1);
_workspaceServices = workspaceServices;
_vsSolution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution));
_runningDocumentTable = (IVsRunningDocumentTable4)serviceProvider.GetService(typeof(SVsRunningDocumentTable));
......@@ -565,5 +574,21 @@ internal void RemoveProjectByBinPath(string filePath, AbstractProject project)
}
}
}
internal void TryDisconnectExistingDeferredProject(IVsHierarchy hierarchy, string projectName)
{
var projectPath = AbstractLegacyProject.GetProjectFilePath(hierarchy);
var projectId = GetOrCreateProjectIdForPath(projectPath, projectName);
// If we created a project for this while in deferred project load mode, let's close it
// now that we're being asked to make a "real" project for it, so that we'll prefer the
// "real" project
if (_workspaceServices.GetService<IDeferredProjectWorkspaceService>()?.IsDeferredProjectLoadEnabled == true)
{
var existingProject = GetProject(projectId);
Debug.Assert(existingProject is IWorkspaceProjectContext);
existingProject?.Disconnect();
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
......@@ -19,6 +21,14 @@ int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
{
AssertIsForeground();
var deferredProjectWorkspaceService = _workspaceServices.GetService<IDeferredProjectWorkspaceService>();
if (deferredProjectWorkspaceService?.IsDeferredProjectLoadEnabled == true)
{
LoadSolutionFromMSBuildAsync(deferredProjectWorkspaceService, _solutionParsingCancellationTokenSource.Token).FireAndForget();
}
return VSConstants.S_OK;
}
......@@ -60,6 +70,11 @@ int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved)
_solutionLoadComplete = false;
// Cancel any background solution parsing. NOTE: This means that that work needs to
// check the token periodically, and whenever resuming from an "await"
_solutionParsingCancellationTokenSource.Cancel();
_solutionParsingCancellationTokenSource = new CancellationTokenSource();
return VSConstants.S_OK;
}
......@@ -67,6 +82,17 @@ int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved)
{
AssertIsForeground();
var deferredProjectWorkspaceService = _workspaceServices.GetService<IDeferredProjectWorkspaceService>();
if (deferredProjectWorkspaceService?.IsDeferredProjectLoadEnabled == true)
{
// Copy to avoid modifying the collection while enumerating
var loadedProjects = ImmutableProjects.ToList();
foreach (var p in loadedProjects)
{
p.Disconnect();
}
}
lock (_gate)
{
Contract.ThrowIfFalse(_projectMap.Count == 0);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.ProjectSystem;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal partial class VisualStudioProjectTracker : IVsSolutionLoadEvents
{
// Temporary for prototyping purposes
private IVsOutputWindowPane _pane;
/// <summary>
/// Used to cancel our background solution parse if we get a solution close event from VS.
/// </summary>
private CancellationTokenSource _solutionParsingCancellationTokenSource = new CancellationTokenSource();
int IVsSolutionLoadEvents.OnBeforeOpenSolution(string pszSolutionFilename)
{
return VSConstants.S_OK;
}
private async Task LoadSolutionFromMSBuildAsync(
IDeferredProjectWorkspaceService deferredProjectWorkspaceService,
CancellationToken cancellationToken)
{
AssertIsForeground();
InitializeOutputPane();
// Continue on the UI thread for these operations, since we are touching the VisualStudioWorkspace, etc.
await PopulateWorkspaceFromDeferredProjectInfoAsync(deferredProjectWorkspaceService, cancellationToken).ConfigureAwait(true);
}
[Conditional("DEBUG")]
private void InitializeOutputPane()
{
var outputWindow = (IVsOutputWindow)_serviceProvider.GetService(typeof(SVsOutputWindow));
var paneGuid = new Guid("07aaa8e9-d776-47d6-a1be-5ce00332d74d");
if (ErrorHandler.Succeeded(outputWindow.CreatePane(ref paneGuid, "Roslyn DPL Status", fInitVisible: 1, fClearWithSolution: 1)) &&
ErrorHandler.Succeeded(outputWindow.GetPane(ref paneGuid, out _pane)) && _pane != null)
{
_pane.Activate();
}
}
int IVsSolutionLoadEvents.OnBeforeBackgroundSolutionLoadBegins()
{
return VSConstants.S_OK;
......@@ -51,6 +95,228 @@ int IVsSolutionLoadEvents.OnAfterBackgroundSolutionLoadComplete()
{
AssertIsForeground();
// In Non-DPL scenarios, this indicates that ASL is complete, and we should push any
// remaining information we have to the Workspace. If DPL is enabled, this is never
// called.
FinishLoad();
return VSConstants.S_OK;
}
private async Task PopulateWorkspaceFromDeferredProjectInfoAsync(
IDeferredProjectWorkspaceService deferredProjectWorkspaceService,
CancellationToken cancellationToken)
{
// NOTE: We need to check cancellationToken after each await, in case the user has
// already closed the solution.
AssertIsForeground();
var componentModel = _serviceProvider.GetService(typeof(SComponentModel)) as IComponentModel;
var workspaceProjectContextFactory = componentModel.GetService<IWorkspaceProjectContextFactory>();
var dte = _serviceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
var solutionConfig = (EnvDTE80.SolutionConfiguration2)dte.Solution.SolutionBuild.ActiveConfiguration;
OutputToOutputWindow($"Getting project information - start");
var start = DateTimeOffset.UtcNow;
// Capture the context so that we come back on the UI thread, and do the actual project creation there.
var projectInfos = await deferredProjectWorkspaceService.GetDeferredProjectInfoForConfigurationAsync(
$"{solutionConfig.Name}|{solutionConfig.PlatformName}",
cancellationToken).ConfigureAwait(true);
AssertIsForeground();
cancellationToken.ThrowIfCancellationRequested();
OutputToOutputWindow($"Getting project information - done (took {DateTimeOffset.UtcNow - start})");
OutputToOutputWindow($"Creating projects - start");
start = DateTimeOffset.UtcNow;
var targetPathsToProjectPaths = BuildTargetPathMap(projectInfos);
foreach (var projectFilename in projectInfos.Keys)
{
cancellationToken.ThrowIfCancellationRequested();
GetOrCreateProjectFromArgumentsAndReferences(
workspaceProjectContextFactory,
projectFilename,
projectInfos,
targetPathsToProjectPaths);
}
OutputToOutputWindow($"Creating projects - done (took {DateTimeOffset.UtcNow - start})");
OutputToOutputWindow($"Pushing to workspace - start");
start = DateTimeOffset.UtcNow;
FinishLoad();
OutputToOutputWindow($"Pushing to workspace - done (took {DateTimeOffset.UtcNow - start})");
}
private static ImmutableDictionary<string, string> BuildTargetPathMap(IReadOnlyDictionary<string, DeferredProjectInformation> projectInfos)
{
var builder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var item in projectInfos)
{
var targetPath = item.Value.TargetPath;
if (targetPath != null)
{
if (!builder.ContainsKey(targetPath))
{
builder[targetPath] = item.Key;
}
else
{
Debug.Fail($"Already have a target path of '{item.Value.TargetPath}', with value '{builder[item.Value.TargetPath]}'.");
}
}
}
return builder.ToImmutable();
}
[Conditional("DEBUG")]
private void OutputToOutputWindow(string message)
{
_pane?.OutputString(message + Environment.NewLine);
}
private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
IWorkspaceProjectContextFactory workspaceProjectContextFactory,
string projectFilename,
IReadOnlyDictionary<string, DeferredProjectInformation> allProjectInfos,
IReadOnlyDictionary<string, string> targetPathsToProjectPaths)
{
var languageName = GetLanguageOfProject(projectFilename);
if (languageName == null)
{
return null;
}
DeferredProjectInformation projectInfo;
if (!allProjectInfos.TryGetValue(projectFilename, out projectInfo))
{
// This could happen if we were called recursively about a dangling P2P reference
// that isn't actually in the solution.
return null;
}
var commandLineParser = _workspaceServices.GetLanguageServices(languageName).GetService<ICommandLineParserService>();
var projectDirectory = Path.GetDirectoryName(projectFilename);
var commandLineArguments = commandLineParser.Parse(
projectInfo.CommandLineArguments,
projectDirectory,
isInteractive: false,
sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
// TODO: Should come from sln file?
var projectName = Path.GetFileNameWithoutExtension(projectFilename);
var projectId = GetOrCreateProjectIdForPath(projectFilename, projectName);
// See if we've already created this project and we're now in a recursive call to
// hook up a P2P ref.
AbstractProject project;
if (_projectMap.TryGetValue(projectId, out project))
{
return project;
}
OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
var solution5 = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;
var projectGuid = solution5.GetGuidOfProjectFile(projectFilename);
var projectContext = workspaceProjectContextFactory.CreateProjectContext(
languageName,
projectName,
projectFilename,
projectGuid: projectGuid,
hierarchy: null,
binOutputPath: projectInfo.TargetPath);
projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));
foreach (var sourceFile in commandLineArguments.SourceFiles)
{
projectContext.AddSourceFile(sourceFile.Path);
}
foreach (var sourceFile in commandLineArguments.AdditionalFiles)
{
projectContext.AddAdditionalFile(sourceFile.Path);
}
var addedProjectReferences = new HashSet<string>();
foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
{
var referencedProject = ImmutableProjects.SingleOrDefault(p => StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath));
if (referencedProject == null)
{
referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
workspaceProjectContextFactory,
projectReferencePath,
allProjectInfos,
targetPathsToProjectPaths);
}
var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
if (referencedProjectContext != null)
{
// TODO: Can we get the properties from corresponding metadata reference in
// commandLineArguments?
addedProjectReferences.Add(projectReferencePath);
projectContext.AddProjectReference(
referencedProjectContext,
new MetadataReferenceProperties());
}
else if (referencedProject != null)
{
// This project was already created by the regular project system. See if we
// can find the matching project somehow.
var existingReferenceOutputPath = referencedProject?.BinOutputPath;
if (existingReferenceOutputPath != null)
{
addedProjectReferences.Add(projectReferencePath);
projectContext.AddMetadataReference(
existingReferenceOutputPath,
new MetadataReferenceProperties());
}
}
else
{
// We don't know how to create this project. Another language or something?
OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
}
}
foreach (var reference in commandLineArguments.MetadataReferences)
{
string possibleProjectReference;
if (targetPathsToProjectPaths.TryGetValue(reference.Reference, out possibleProjectReference) &&
addedProjectReferences.Contains(possibleProjectReference))
{
// We already added a P2P reference for this, we don't need to add the file reference too.
continue;
}
projectContext.AddMetadataReference(reference.Reference, reference.Properties);
}
foreach (var reference in commandLineArguments.AnalyzerReferences)
{
projectContext.AddAnalyzerReference(reference.FilePath);
}
return (AbstractProject)projectContext;
}
private static string GetLanguageOfProject(string projectFilename)
{
switch (Path.GetExtension(projectFilename))
{
case ".csproj":
return LanguageNames.CSharp;
case ".vbproj":
return LanguageNames.VisualBasic;
default:
return null;
};
}
private void FinishLoad()
{
// We are now completely done, so let's simply ensure all projects are added.
StartPushingToWorkspaceAndNotifyOfOpenDocuments_Foreground(this.ImmutableProjects);
......@@ -59,8 +325,6 @@ int IVsSolutionLoadEvents.OnAfterBackgroundSolutionLoadComplete()
// Check that the set of analyzers is complete and consistent.
GetAnalyzerDependencyCheckingService()?.CheckForConflictsAsync();
return VSConstants.S_OK;
}
private AnalyzerDependencyCheckingService GetAnalyzerDependencyCheckingService()
......
......@@ -79,7 +79,7 @@ internal static HostServices CreateHostServices(SVsServiceProvider serviceProvid
protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider serviceProvider, SaveEventsService saveEventsService)
{
var projectTracker = new VisualStudioProjectTracker(serviceProvider);
var projectTracker = new VisualStudioProjectTracker(serviceProvider, this.Services);
// Ensure the document tracking service is initialized on the UI thread
var documentTrackingService = this.Services.GetService<IDocumentTrackingService>();
......@@ -145,8 +145,36 @@ private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject
Microsoft.CodeAnalysis.Solution newSolution,
IProgressTracker progressTracker)
{
var projectChanges = newSolution.GetChanges(this.CurrentSolution).GetProjectChanges().ToList();
var projectsToLoad = new HashSet<Guid>();
foreach (var pc in projectChanges)
{
if (pc.GetAddedAdditionalDocuments().Any() ||
pc.GetAddedAnalyzerReferences().Any() ||
pc.GetAddedDocuments().Any() ||
pc.GetAddedMetadataReferences().Any() ||
pc.GetAddedProjectReferences().Any() ||
pc.GetRemovedAdditionalDocuments().Any() ||
pc.GetRemovedAnalyzerReferences().Any() ||
pc.GetRemovedDocuments().Any() ||
pc.GetRemovedMetadataReferences().Any() ||
pc.GetRemovedProjectReferences().Any())
{
projectsToLoad.Add(GetHostProject(pc.ProjectId).Guid);
}
}
if (projectsToLoad.Any())
{
var vsSolution4 = GetVsService(typeof(SVsSolution)) as IVsSolution4;
vsSolution4.EnsureProjectsAreLoaded(
(uint)projectsToLoad.Count,
projectsToLoad.ToArray(),
(uint)__VSBSLFLAGS.VSBSLFLAGS_None);
}
// first make sure we can edit the document we will be updating (check them out from source control, etc)
var changedDocs = newSolution.GetChanges(this.CurrentSolution).GetProjectChanges().SelectMany(pd => pd.GetChangedDocuments()).ToList();
var changedDocs = projectChanges.SelectMany(pd => pd.GetChangedDocuments()).ToList();
if (changedDocs.Count > 0)
{
this.EnsureEditableDocuments(changedDocs);
......
......@@ -90,6 +90,7 @@
<Compile Include="Implementation\Preview\ReferenceChange.ProjectReferenceChange.cs" />
<Compile Include="Implementation\Preview\ReferenceChange.cs" />
<Compile Include="Implementation\ProjectSystem\CPS\ICodeModelFactory.cs" />
<Compile Include="Implementation\ProjectSystem\IDeferredProjectWorkspaceService.cs" />
<Compile Include="Implementation\ProjectSystem\Legacy\AbstractLegacyProject_ICompilerOptionsHostObject.cs" />
<Compile Include="Implementation\ProjectSystem\Legacy\AbstractLegacyProject_IIntellisenseBuildTarget.cs" />
<Compile Include="Implementation\ProjectSystem\CPS\IWorkspaceProjectContextFactory.cs" />
......
......@@ -66,7 +66,7 @@ internal CodeModelProjectCache GetCodeModelCache()
public bool TryGetCachedFileCodeModel(string fileName, out ComHandle<EnvDTE80.FileCodeModel2, FileCodeModel> fileCodeModelHandle)
{
var handle = GetCodeModelCache().GetComHandleForFileCodeModel(fileName);
var handle = GetCodeModelCache()?.GetComHandleForFileCodeModel(fileName);
fileCodeModelHandle = handle != null
? handle.Value
......
......@@ -43,13 +43,22 @@ internal sealed partial class CPSProject : AbstractProject
// We might we invoked from a background thread, so schedule the disconnect on foreground task scheduler.
public sealed override void Disconnect()
{
InvokeBelowInputPriority(() =>
if (IsForeground())
{
// clear code model cache and shutdown instances, if any exists.
_projectCodeModel?.OnProjectClosed();
DisconnectCore();
}
else
{
InvokeBelowInputPriority(DisconnectCore);
}
}
private void DisconnectCore()
{
// clear code model cache and shutdown instances, if any exists.
_projectCodeModel?.OnProjectClosed();
base.Disconnect();
});
base.Disconnect();
}
}
}
......@@ -59,13 +59,9 @@ internal static CPSProject CreateCPSProject(VisualStudioProjectTracker projectTr
object hierarchy,
string binOutputPath)
{
Contract.ThrowIfNull(hierarchy);
// NOTE: It is acceptable for hierarchy to be null in Deferred Project Load scenarios.
var vsHierarchy = hierarchy as IVsHierarchy;
if (vsHierarchy == null)
{
throw new ArgumentException(nameof(hierarchy));
}
Func<ProjectId, IVsReportExternalErrors> getExternalErrorReporter = id => GetExternalErrorReporter(id, languageName);
return new CPSProject(_visualStudioWorkspace.ProjectTracker, getExternalErrorReporter, projectDisplayName, projectFilePath,
vsHierarchy, languageName, projectGuid, binOutputPath, _serviceProvider, _visualStudioWorkspace, _hostDiagnosticUpdateSource,
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.ProjectSystem;
using Roslyn.Utilities;
......@@ -108,29 +109,14 @@ public new void RemoveMetadataReference(string referencePath)
public void AddProjectReference(IWorkspaceProjectContext project, MetadataReferenceProperties properties)
{
var abstractProject = GetAbstractProject(project);
// AbstractProject and ProjectTracker track project references using the project bin output path.
// Setting the command line arguments should have already set the output file name and folder.
// We fetch this output path to add the reference.
var referencedProject = this.ProjectTracker.GetProject(abstractProject.Id);
var binPathOpt = referencedProject.BinOutputPath;
if (!string.IsNullOrEmpty(binPathOpt))
{
AddMetadataReferenceAndTryConvertingToProjectReferenceIfPossible(binPathOpt, properties);
}
AddProjectReference(new ProjectReference(abstractProject.Id, properties.Aliases, properties.EmbedInteropTypes));
}
public void RemoveProjectReference(IWorkspaceProjectContext project)
{
var referencedProject = GetAbstractProject(project);
// AbstractProject and ProjectTracker track project references using the project bin output path.
// We fetch this output path to remove the reference.
var binPathOpt = referencedProject.BinOutputPath;
if (!string.IsNullOrEmpty(binPathOpt))
{
base.RemoveMetadataReference(binPathOpt);
}
var projectReference = GetCurrentProjectReferences().Single(p => p.ProjectId == referencedProject.Id);
RemoveProjectReference(projectReference);
}
private AbstractProject GetAbstractProject(IWorkspaceProjectContext project)
......@@ -148,7 +134,7 @@ private AbstractProject GetAbstractProject(IWorkspaceProjectContext project)
#region Files
public void AddSourceFile(string filePath, bool isInCurrentContext = true, IEnumerable<string> folderNames = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
{
AddFile(filePath, sourceCodeKind, getIsCurrentContext: _ => isInCurrentContext, folderNames: folderNames.ToImmutableArrayOrEmpty());
AddFile(filePath, sourceCodeKind, _ => isInCurrentContext, _ => folderNames.ToImmutableArrayOrEmpty());
}
public void RemoveSourceFile(string filePath)
......
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Workspace.Extensions;
using Microsoft.VisualStudio.Workspace.VSIntegration;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.ProjectSystem
{
[ExportWorkspaceService(typeof(IDeferredProjectWorkspaceService)), Shared]
internal class DeferredProjectWorkspaceService : IDeferredProjectWorkspaceService
{
private readonly IVsSolutionWorkspaceService _solutionWorkspaceService;
private readonly IVsSolution7 _solution7;
[ImportingConstructor]
public DeferredProjectWorkspaceService(SVsServiceProvider serviceProvider)
{
_solutionWorkspaceService = serviceProvider.GetService(typeof(SVsSolutionWorkspaceService)) as IVsSolutionWorkspaceService;
_solution7 = serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution7;
}
public bool IsDeferredProjectLoadEnabled => _solution7?.IsSolutionLoadDeferred() == true;
public async Task<IReadOnlyDictionary<string, DeferredProjectInformation>> GetDeferredProjectInfoForConfigurationAsync(
string solutionConfiguration,
CancellationToken cancellationToken)
{
var commandLineInfos = await _solutionWorkspaceService.GetManagedCommandLineInfoAsync(
solutionConfiguration, cancellationToken).ConfigureAwait(false);
// NOTE: Anycode gives us the project references as if they were command line arguments with
// "/ProjectReference:" prepended. Strip that off here.
var result = ImmutableDictionary.CreateRange(
commandLineInfos.Select(kvp => KeyValuePair.Create(
kvp.Key,
new DeferredProjectInformation(
kvp.Value.TargetPath,
kvp.Value.CommandLineArgs,
kvp.Value.ProjectReferences.Select(p => p.Substring("/ProjectReference:".Length)).ToImmutableArray()))));
return result;
}
}
}
......@@ -9,6 +9,8 @@
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
using Workspace = Microsoft.CodeAnalysis.Workspace;
[ExportWorkspaceService(typeof(IRemoteHostClientFactory)), Shared]
internal class RemoteHostClientFactory : IRemoteHostClientFactory
{
......@@ -28,4 +30,4 @@ public Task<RemoteHostClient> CreateAsync(Workspace workspace, CancellationToken
}
}
}
}
\ No newline at end of file
}
......@@ -15,6 +15,8 @@
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
using Workspace = Microsoft.CodeAnalysis.Workspace;
internal partial class ServiceHubRemoteHostClient : RemoteHostClient
{
private readonly HubClient _hubClient;
......
......@@ -106,6 +106,7 @@
<Compile Include="FindReferences\StreamingFindReferencesPresenter.TableDataSourceFindReferencesContext.cs" />
<Compile Include="FindReferences\StreamingFindReferencesPresenter.TableEntriesSnapshot.cs" />
<Compile Include="FindReferences\TaggedTextAndHighlightSpan.cs" />
<Compile Include="ProjectSystem\DeferredProjectWorkspaceService.cs" />
<Compile Include="Remote\JsonRpcClient.cs" />
<Compile Include="Remote\JsonRpcSession.cs" />
<Compile Include="Remote\RemoteHostClientFactory.cs" />
......@@ -130,4 +131,4 @@
<InternalsVisibleToTest Include="Roslyn.VisualStudio.Next.UnitTests" />
</ItemGroup>
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</Project>
\ No newline at end of file
</Project>
......@@ -12,9 +12,11 @@
},
"Microsoft.ServiceHub.Client": "1.0.103-rc",
"Newtonsoft.Json": "8.0.3",
"RoslynDependencies.Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime": "15.0.25718-Preview5",
"RoslynDependencies.Microsoft.VisualStudio.Workspace": "14.0.983-pre-ge167e81694",
"System.Collections.Immutable": "1.2.0"
},
"frameworks": {
"net46": { }
}
}
\ No newline at end of file
}
......@@ -38,8 +38,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Fr
_monitorSelectionMock = New MockShellMonitorSelection(solutionIsFullyLoaded)
_serviceProvider = New MockServiceProvider(_monitorSelectionMock)
_projectTracker = New VisualStudioProjectTracker(_serviceProvider)
_workspace = New TestWorkspace()
_projectTracker = New VisualStudioProjectTracker(_serviceProvider, _workspace.Services)
Dim metadataReferenceProvider = New VisualStudioMetadataReferenceManager(_serviceProvider, _workspace.Services.GetService(Of ITemporaryStorageService)())
Dim ruleSetFileProvider = New VisualStudioRuleSetManager(
DirectCast(_serviceProvider.GetService(GetType(SVsFileChangeEx)), IVsFileChangeEx),
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeLens;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
using Microsoft.VisualStudio.LanguageServices.Remote;
namespace Microsoft.VisualStudio.LanguageServices.CodeLens
{
[ExportWorkspaceService(typeof(ICodeLensReferencesService), layer: ServiceLayer.Host), Shared]
internal sealed class RemoteCodeLensReferencesService : ICodeLensReferencesService
{
public async Task<ReferenceCount> GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync(solution, documentId, syntaxNode, maxSearchResults, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<ReferenceCount>(WellKnownServiceHubServices.CodeAnalysisService_GetReferenceCountAsync, new CodeLensArguments(documentId, syntaxNode), maxSearchResults).ConfigureAwait(false);
}
}
public async Task<IEnumerable<ReferenceLocationDescriptor>> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<IEnumerable<ReferenceLocationDescriptor>>(WellKnownServiceHubServices.CodeAnalysisService_FindReferenceLocationsAsync, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
public async Task<IEnumerable<ReferenceMethodDescriptor>> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<IEnumerable<ReferenceMethodDescriptor>>(WellKnownServiceHubServices.CodeAnalysisService_FindReferenceMethodsAsync, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
public async Task<string> GetFullyQualifiedName(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
var remoteHostClient = await solution.Workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
// remote host is not running. this can happen if remote host is disabled.
return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedName(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
// TODO: send telemetry on session
using (var session = await remoteHostClient.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
return await session.InvokeAsync<string>(WellKnownServiceHubServices.CodeAnalysisService_GetFullyQualifiedName, new CodeLensArguments(documentId, syntaxNode)).ConfigureAwait(false);
}
}
}
}
......@@ -4,7 +4,9 @@ Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Legacy
Imports Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
Imports Microsoft.VisualStudio.LanguageServices.ProjectSystem
Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim
Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.Interop
Imports Microsoft.VisualStudio.Shell.Interop
......@@ -19,17 +21,19 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Function
Public Function CreateProject(wszName As String, punkProject As Object, pProjHier As IVsHierarchy, pVbCompilerHost As IVbCompilerHost) As IVbCompilerProject Implements IVbCompiler.CreateProject
Dim visualStudioWorkspace = ComponentModel.GetService(Of VisualStudioWorkspaceImpl)()
Dim hostDiagnosticUpdateSource = ComponentModel.GetService(Of HostDiagnosticUpdateSource)()
Workspace.ProjectTracker.TryDisconnectExistingDeferredProject(pProjHier, wszName)
Return New VisualBasicProjectShimWithServices(
visualStudioWorkspace.ProjectTracker,
Workspace.ProjectTracker,
pVbCompilerHost,
wszName,
pProjHier,
Me,
visualStudioWorkspace,
Workspace,
hostDiagnosticUpdateSource,
commandLineParserServiceOpt:=visualStudioWorkspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetService(Of ICommandLineParserService))
commandLineParserServiceOpt:=Workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetService(Of ICommandLineParserService))
End Function
Public Function IsValidIdentifier(wszIdentifier As String) As Boolean Implements IVbCompiler.IsValidIdentifier
......
......@@ -104,7 +104,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim
' We trust the project system to only tell us about files that we can use.
Dim canUseTextBuffer As Func(Of ITextBuffer, Boolean) = Function(t) True
MyBase.AddFile(wszFileName, SourceCodeKind.Regular, itemid)
MyBase.AddFile(wszFileName, SourceCodeKind.Regular)
Catch e As Exception When FilterException(e)
Throw ExceptionUtilities.Unreachable
End Try
......
......@@ -16,6 +16,7 @@
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Xaml
{
......@@ -142,7 +143,9 @@ private AbstractProject GetXamlProject(IVsHierarchy hierarchy)
private bool TryCreateXamlDocument(AbstractProject project, string filePath, out IVisualStudioHostDocument vsDocument)
{
vsDocument = _vsWorkspace.ProjectTracker.DocumentProvider.TryGetDocumentForFile(
project, ImmutableArray<string>.Empty, filePath, SourceCodeKind.Regular, tb => tb.ContentType.IsOfType(ContentTypeNames.XamlContentType));
project, filePath, SourceCodeKind.Regular,
tb => tb.ContentType.IsOfType(ContentTypeNames.XamlContentType),
_ => SpecializedCollections.EmptyReadOnlyList<string>());
return vsDocument != null;
}
......
......@@ -14,6 +14,21 @@ namespace Roslyn.Utilities
[SuppressMessage("ApiDesign", "CA1068", Justification = "Matching TPL Signatures")]
internal static partial class TaskExtensions
{
/// <summary>
/// Use to explicitly indicate that you are not waiting for a task to complete
/// Observes the exceptions from it.
/// </summary>
public static async void FireAndForget(this Task task)
{
try
{
await task.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
}
public static T WaitAndGetResult<T>(this Task<T> task, CancellationToken cancellationToken)
{
#if DEBUG
......
......@@ -26,4 +26,4 @@ internal static class RoslynServices
public static readonly SolutionService SolutionService = new SolutionService();
public static readonly CompilationService CompilationService = new CompilationService();
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册