提交 5e1831af 编写于 作者: J Jason Malinowski

Defer the initialization of a VisualStudioWorkspace until necessary

Previously, when a VisualStudioWorkspace was constructed we were
doing a bunch of work in the constructor talking to the UI thread. This
was dangerous because we might get composed on a background thread.
This moves the dangerous initialization until we're creating a project
when we know we have a UI thread available.

In this refactoring I moved the project tracker and a few other fields
into a private class so it's more obvious what's dangerous to touch.
I also do a pass through all consumers of the property and either
update it to use the deferred state directly (because we're only
consuming projects, so it's fine if we don't have anything) or to the
factory method if we actually are creating projects.

This does temporarily regress the ability to create projects on
background threads, but it was unclear if that was generally safe to
start with.
上级 f9a60489
......@@ -19,11 +19,14 @@ 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 projectTracker = Workspace.GetProjectTrackerAndInitializeIfNecessary(SystemServiceProvider);
projectTracker.TryDisconnectExistingDeferredProject(hierarchy, projectName);
var project = new CSharpProjectShimWithServices(
projectRoot,
this.Workspace.ProjectTracker,
projectTracker,
id => new ProjectExternalErrorReporter(id, "CS", this.SystemServiceProvider),
projectName,
hierarchy,
......
......@@ -81,7 +81,7 @@ public async void CheckForConflictsAsync()
var conflicts = results.Conflicts;
var missingDependencies = results.MissingDependencies;
foreach (var project in _workspace.ProjectTracker.ImmutableProjects)
foreach (var project in _workspace.DeferredState.ProjectTracker.ImmutableProjects)
{
builder.Clear();
......
......@@ -142,7 +142,7 @@ private void Tracker_UpdatedOnDisk(object sender, EventArgs e)
// Traverse the chain of requesting assemblies to get back to the original analyzer
// assembly.
var projectsWithAnalyzer = _workspace.ProjectTracker.ImmutableProjects.Where(p => p.CurrentProjectAnalyzersContains(filePath)).ToArray();
var projectsWithAnalyzer = _workspace.DeferredState.ProjectTracker.ImmutableProjects.Where(p => p.CurrentProjectAnalyzersContains(filePath)).ToArray();
foreach (var project in projectsWithAnalyzer)
{
RaiseAnalyzerChangedWarning(project.Id, filePath);
......
......@@ -35,7 +35,7 @@ public VisualStudioDiagnosticAnalyzerService(VisualStudioWorkspaceImpl workspace
}
// Analyzers are only supported for C# and VB currently.
var projectsWithHierarchy = _workspace.ProjectTracker.ImmutableProjects
var projectsWithHierarchy = (_workspace.DeferredState?.ProjectTracker.ImmutableProjects ?? ImmutableArray<AbstractProject>.Empty)
.Where(p => p.Language == LanguageNames.CSharp || p.Language == LanguageNames.VisualBasic)
.Where(p => p.Hierarchy == hierarchyOpt)
.Select(p => _workspace.CurrentSolution.GetProject(p.Id));
......
......@@ -87,7 +87,7 @@ private void SetReadOnly(Document document)
{
// Only set documents read-only if they're part of a project that supports Enc.
var workspace = document.Project.Solution.Workspace as VisualStudioWorkspaceImpl;
var project = workspace?.ProjectTracker?.GetProject(document.Project.Id);
var project = workspace?.DeferredState?.ProjectTracker?.GetProject(document.Project.Id);
if (project?.EditAndContinueImplOpt != null)
{
......
......@@ -63,7 +63,7 @@ private AbstractProject FindMatchingProject(IVsHierarchy hierarchy, uint itemid)
return null;
}
return this.Workspace.ProjectTracker.ImmutableProjects
return this.Workspace.DeferredState.ProjectTracker.ImmutableProjects
.Where(p => p.Hierarchy == hierarchy)
.Where(p => p.ProjectSystemName == projectName)
.SingleOrDefault();
......
// 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.Text;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
......@@ -52,19 +53,7 @@ public static string GetProjectDisplayName(this Project project)
var workspace = project.Solution.Workspace as VisualStudioWorkspaceImpl;
if (workspace != null)
{
var hierarchy = workspace.GetHierarchy(project.Id);
if (hierarchy != null)
{
var solution = workspace.GetVsService<SVsSolution, IVsSolution3>();
if (solution != null)
{
string name;
if (ErrorHandler.Succeeded(solution.GetUniqueUINameOfProject(hierarchy, out name)) && name != null)
{
return name;
}
}
}
return workspace.GetProjectDisplayName(project);
}
return project.Name;
......
......@@ -404,7 +404,8 @@ private static async Task<Uri> GetAssemblyFullPathAsync(IAssemblySymbol containi
var workspace = solution.Workspace as VisualStudioWorkspaceImpl;
if (workspace != null)
{
var vsProject = workspace.ProjectTracker.GetProject(foundProject.Id);
// We have found a project in the solution, so clearly the deferred state has been loaded
var vsProject = workspace.DeferredState.ProjectTracker.GetProject(foundProject.Id);
if (vsProject != null)
{
var output = vsProject.BinOutputPath;
......
......@@ -3,6 +3,7 @@
using System;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
namespace Microsoft.VisualStudio.LanguageServices.ProjectSystem
{
......@@ -14,7 +15,7 @@ internal interface IWorkspaceProjectContextFactory
/// <summary>
/// Creates and initializes a new Workspace project and returns a <see cref="IWorkspaceProjectContext"/> to lazily initialize the properties and items for the project.
/// This method can be invoked on a background thread and doesn't access any members of the given UI <paramref name="hierarchy"/>,
/// allowing the UI hierarchy to be published lazily.
/// allowing the UI hierarchy to be published lazily, as long as <see cref="VisualStudioWorkspaceImpl.GetProjectTrackerAndInitializeIfNecessary"/> has been called once.
/// </summary>
/// <param name="languageName">Project language.</param>
/// <param name="projectDisplayName">Display name for the project.</param>
......@@ -27,7 +28,7 @@ internal interface IWorkspaceProjectContextFactory
/// <summary>
/// Creates and initializes a new Workspace project and returns a <see cref="IWorkspaceProjectContext"/> to lazily initialize the properties and items for the project.
/// This method can be invoked on a background thread and doesn't access any members of the given UI <paramref name="hierarchy"/>,
/// allowing the UI hierarchy to be published lazily.
/// allowing the UI hierarchy to be published lazily, as long as <see cref="VisualStudioWorkspaceImpl.GetProjectTrackerAndInitializeIfNecessary"/> has been called once.
/// </summary>
/// <param name="languageName">Project language.</param>
/// <param name="projectDisplayName">Display name for the project.</param>
......
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal abstract partial class VisualStudioWorkspaceImpl
{
/// <summary>
/// The class that's created once the <see cref="VisualStudioWorkspace"/> is finally
/// getting content inside of it. We have various bits of the implementation
/// of this workspace that need to start up on the UI thread, but we cannot
/// guarantee which thread will create the <see cref="VisualStudioWorkspace"/>,
/// since it could be MEF imported on any thread. This class holds all that "real" state
/// which can't be touched during construction or in any codepath that
/// might run before a project is added.
/// </summary>
internal class DeferredInitializationState : ForegroundThreadAffinitizedObject
{
public VisualStudioProjectTracker ProjectTracker { get; }
public IServiceProvider ServiceProvider { get; }
public IVsUIShellOpenDocument ShellOpenDocumentService { get; }
public DeferredInitializationState(VisualStudioWorkspaceImpl workspace, IServiceProvider serviceProvider)
: base(assertIsForeground: true)
{
ServiceProvider = serviceProvider;
ShellOpenDocumentService = (IVsUIShellOpenDocument)serviceProvider.GetService(typeof(SVsUIShellOpenDocument));
ProjectTracker = new VisualStudioProjectTracker(serviceProvider, workspace.Services);
// Ensure the document tracking service is initialized on the UI thread
var documentTrackingService = workspace.Services.GetService<IDocumentTrackingService>();
var documentProvider = new RoslynDocumentProvider(ProjectTracker, serviceProvider, documentTrackingService);
var metadataReferenceProvider = workspace.Services.GetService<VisualStudioMetadataReferenceManager>();
var ruleSetFileProvider = workspace.Services.GetService<VisualStudioRuleSetManager>();
ProjectTracker.InitializeProviders(documentProvider, metadataReferenceProvider, ruleSetFileProvider);
var workspaceHost = new VisualStudioWorkspaceHost(workspace);
ProjectTracker.RegisterWorkspaceHost(workspaceHost);
ProjectTracker.StartSendingEventsToWorkspaceHost(workspaceHost);
var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
var saveEventsService = componentModel.GetService<SaveEventsService>();
saveEventsService.StartSendingSaveEvents();
// Ensure the options factory services are initialized on the UI thread
workspace.Services.GetService<IOptionService>();
}
}
internal string GetProjectDisplayName(Project project)
{
var hierarchy = this.GetHierarchy(project.Id);
if (hierarchy != null)
{
var solution = (IVsSolution3)DeferredState.ServiceProvider.GetService(typeof(SVsSolution));
if (solution != null)
{
string name;
if (ErrorHandler.Succeeded(solution.GetUniqueUINameOfProject(hierarchy, out name)) && name != null)
{
return name;
}
}
}
return project.Name;
}
}
}
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Text;
......@@ -43,79 +44,61 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac
private static readonly IntPtr s_docDataExisting_Unknown = new IntPtr(-1);
private const string AppCodeFolderName = "App_Code";
protected readonly IServiceProvider ServiceProvider;
private readonly IVsUIShellOpenDocument _shellOpenDocument;
private readonly IVsTextManager _textManager;
// Not readonly because it needs to be set in the derived class' constructor.
private VisualStudioProjectTracker _projectTracker;
// document worker coordinator
private ISolutionCrawlerRegistrationService _registrationService;
private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject();
public VisualStudioWorkspaceImpl(
SVsServiceProvider serviceProvider,
WorkspaceBackgroundWork backgroundWork)
: base(
CreateHostServices(serviceProvider),
backgroundWork)
{
this.ServiceProvider = serviceProvider;
_textManager = serviceProvider.GetService(typeof(SVsTextManager)) as IVsTextManager;
_shellOpenDocument = serviceProvider.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
/// <summary>
/// A <see cref="ForegroundThreadAffinitizedObject"/> to make assertions that stuff is on the right thread.
/// </summary>
private readonly ForegroundThreadAffinitizedObject _foregroundObject
= new ForegroundThreadAffinitizedObject(assertIsForeground: false);
// Ensure the options factory services are initialized on the UI thread
this.Services.GetService<IOptionService>();
}
/// <summary>
/// The <see cref="DeferredInitializationState"/> that consists of the <see cref="VisualStudioProjectTracker" />
/// and other UI-initialized types. It will be created as long as a single project has been created.
/// </summary>
internal DeferredInitializationState DeferredState { get; private set; }
internal static HostServices CreateHostServices(SVsServiceProvider serviceProvider)
public VisualStudioWorkspaceImpl(ExportProvider exportProvider)
: base(
MefV1HostServices.Create(exportProvider),
backgroundWork: WorkspaceBackgroundWork.ParseAndCompile)
{
var composition = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
return MefV1HostServices.Create(composition.DefaultExportProvider);
PrimaryWorkspace.Register(this);
}
protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider serviceProvider, SaveEventsService saveEventsService)
/// <summary>
/// Ensures the workspace is fully hooked up to the host by subscribing to all sorts of VS
/// UI thread affinitized events.
/// </summary>
internal VisualStudioProjectTracker GetProjectTrackerAndInitializeIfNecessary(IServiceProvider 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>();
var documentProvider = new RoslynDocumentProvider(projectTracker, serviceProvider, documentTrackingService);
var metadataReferenceProvider = this.Services.GetService<VisualStudioMetadataReferenceManager>();
var ruleSetFileProvider = this.Services.GetService<VisualStudioRuleSetManager>();
projectTracker.InitializeProviders(documentProvider, metadataReferenceProvider, ruleSetFileProvider);
this.SetProjectTracker(projectTracker);
var workspaceHost = new VisualStudioWorkspaceHost(this);
projectTracker.RegisterWorkspaceHost(workspaceHost);
projectTracker.StartSendingEventsToWorkspaceHost(workspaceHost);
saveEventsService.StartSendingSaveEvents();
// Ensure the options factory services are initialized on the UI thread
this.Services.GetService<IOptionService>();
}
if (DeferredState == null)
{
_foregroundObject.AssertIsForeground();
DeferredState = new DeferredInitializationState(this, serviceProvider);
}
/// <summary>NOTE: Call only from derived class constructor</summary>
protected void SetProjectTracker(VisualStudioProjectTracker projectTracker)
{
_projectTracker = projectTracker;
return DeferredState.ProjectTracker;
}
/// <summary>
/// A compatibility shim to ensure that F# and TypeScript continue to work after the deferred work goes in. This will be
/// removed once they move to calling <see cref="GetProjectTrackerAndInitializeIfNecessary"/>.
/// </summary>
[Obsolete("You should use " + nameof(GetProjectTrackerAndInitializeIfNecessary) + " or check through " + nameof(DeferredState))]
internal VisualStudioProjectTracker ProjectTracker
{
get
{
return _projectTracker;
_foregroundObject.AssertIsForeground();
return GetProjectTrackerAndInitializeIfNecessary(ServiceProvider.GlobalProvider);
}
}
internal void ClearReferenceCache()
{
_projectTracker.MetadataReferenceProvider.ClearCache();
DeferredState?.ProjectTracker.MetadataReferenceProvider.ClearCache();
}
internal IVisualStudioHostDocument GetHostDocument(DocumentId documentId)
......@@ -131,7 +114,7 @@ internal IVisualStudioHostDocument GetHostDocument(DocumentId documentId)
internal IVisualStudioHostProject GetHostProject(ProjectId projectId)
{
return this.ProjectTracker.GetProject(projectId);
return DeferredState.ProjectTracker.GetProject(projectId);
}
private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject project)
......@@ -165,7 +148,7 @@ private bool TryGetHostProject(ProjectId projectId, out IVisualStudioHostProject
if (projectsToLoad.Any())
{
var vsSolution4 = GetVsService(typeof(SVsSolution)) as IVsSolution4;
var vsSolution4 = (IVsSolution4)DeferredState.ServiceProvider.GetService(typeof(SVsSolution));
vsSolution4.EnsureProjectsAreLoaded(
(uint)projectsToLoad.Count,
projectsToLoad.ToArray(),
......@@ -444,7 +427,7 @@ private OleInterop.IOleUndoManager TryGetUndoManager()
var documentId = documentTrackingService.GetActiveDocument() ?? documentTrackingService.GetVisibleDocuments().FirstOrDefault();
if (documentId != null)
{
var composition = (IComponentModel)ServiceProvider.GetService(typeof(SComponentModel));
var composition = (IComponentModel)this.DeferredState.ServiceProvider.GetService(typeof(SComponentModel));
var exportProvider = composition.DefaultExportProvider;
var editorAdaptersService = exportProvider.GetExportedValue<IVsEditorAdaptersFactoryService>();
......@@ -658,7 +641,7 @@ protected override void AddExistingDocument(DocumentId documentId, string filePa
}
}
using (var documentIdHint = _projectTracker.DocumentProvider.ProvideDocumentIdHint(filePath, documentId))
using (var documentIdHint = DeferredState.ProjectTracker.DocumentProvider.ProvideDocumentIdHint(filePath, documentId))
{
return projectItems.AddFromFile(filePath);
}
......@@ -763,7 +746,7 @@ private bool TryGetFrame(IVisualStudioHostDocument document, out IVsWindowFrame
IVsUIHierarchy uiHierarchy;
OLEServiceProvider oleServiceProvider;
return ErrorHandler.Succeeded(_shellOpenDocument.OpenDocumentViaProject(
return ErrorHandler.Succeeded(DeferredState.ShellOpenDocumentService.OpenDocumentViaProject(
document.FilePath,
VSConstants.LOGVIEWID.TextView_guid,
out oleServiceProvider,
......@@ -805,7 +788,7 @@ public void CloseDocumentCore(DocumentId documentId)
IVsUIHierarchy uiHierarchy;
IVsWindowFrame frame;
int isOpen;
if (ErrorHandler.Succeeded(_shellOpenDocument.IsDocumentOpen(null, 0, document.FilePath, Guid.Empty, 0, out uiHierarchy, null, out frame, out isOpen)))
if (ErrorHandler.Succeeded(DeferredState.ShellOpenDocumentService.IsDocumentOpen(null, 0, document.FilePath, Guid.Empty, 0, out uiHierarchy, null, out frame, out isOpen)))
{
// TODO: do we need save argument for CloseDocument?
frame.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave);
......@@ -881,7 +864,7 @@ internal override void SetDocumentContext(DocumentId documentId)
if (sharedHierarchy.SetProperty(
(uint)VSConstants.VSITEMID.Root,
(int)__VSHPROPID8.VSHPROPID_ActiveIntellisenseProjectContext,
ProjectTracker.GetProject(documentId.ProjectId).ProjectSystemName) == VSConstants.S_OK)
DeferredState.ProjectTracker.GetProject(documentId.ProjectId).ProjectSystemName) == VSConstants.S_OK)
{
// The ASP.NET 5 intellisense project is now updated.
return;
......@@ -917,7 +900,7 @@ internal void UpdateDocumentContextIfContainsDocument(IVsHierarchy sharedHierarc
// Note that if there is a single head project and it's in the process of being unloaded
// there might not be a host project.
var hostProject = LinkedFileUtilities.GetContextHostProject(sharedHierarchy, ProjectTracker);
var hostProject = LinkedFileUtilities.GetContextHostProject(sharedHierarchy, DeferredState.ProjectTracker);
if (hostProject?.Hierarchy == sharedHierarchy)
{
return;
......@@ -971,7 +954,7 @@ internal override DocumentId GetDocumentIdInCurrentContext(DocumentId documentId
}
// This is a closed shared document, so we must determine the correct context.
var hostProject = LinkedFileUtilities.GetContextHostProject(sharedHierarchy, ProjectTracker);
var hostProject = LinkedFileUtilities.GetContextHostProject(sharedHierarchy, DeferredState.ProjectTracker);
var matchingProject = CurrentSolution.GetProject(hostProject.Id);
if (matchingProject == null || hostProject.Hierarchy == sharedHierarchy)
{
......@@ -1050,7 +1033,7 @@ protected override void Dispose(bool finalize)
public void EnsureEditableDocuments(IEnumerable<DocumentId> documents)
{
var queryEdit = (IVsQueryEditQuerySave2)ServiceProvider.GetService(typeof(SVsQueryEditQuerySave));
var queryEdit = (IVsQueryEditQuerySave2)DeferredState.ServiceProvider.GetService(typeof(SVsQueryEditQuerySave));
var fileNames = documents.Select(GetFilePath).ToArray();
......@@ -1096,13 +1079,6 @@ internal void OnAdditionalDocumentTextUpdatedOnDisk(DocumentId documentId)
this.OnAdditionalDocumentTextLoaderChanged(documentId, vsDoc.Loader);
}
public TInterface GetVsService<TService, TInterface>()
where TService : class
where TInterface : class
{
return this.ServiceProvider.GetService(typeof(TService)) as TInterface;
}
internal override bool CanAddProjectReference(ProjectId referencingProject, ProjectId referencedProject)
{
_foregroundObject.AssertIsForeground();
......@@ -1170,7 +1146,7 @@ internal override bool CanAddProjectReference(ProjectId referencingProject, Proj
// In both directions things are still unknown. Fallback to the reference manager
// to make the determination here.
var referenceManager = GetVsService<SVsReferenceManager, IVsReferenceManager>();
var referenceManager = (IVsReferenceManager)DeferredState.ServiceProvider.GetService(typeof(SVsReferenceManager));
if (referenceManager == null)
{
// Couldn't get the reference manager. Have to assume it's not allowed.
......@@ -1439,7 +1415,7 @@ void IVisualStudioWorkingFolder.OnAfterWorkingFolderChange()
{
var solutionId = _workspace.CurrentSolution.Id;
_workspace.ProjectTracker.UpdateSolutionProperties(solutionId);
_workspace.DeferredState.ProjectTracker.UpdateSolutionProperties(solutionId);
RegisterPrimarySolutionForPersistentStorage(solutionId);
}
}
......
......@@ -117,7 +117,7 @@ public bool RemoveSuppressions(bool selectedErrorListEntriesOnly, IVsHierarchy p
}
else
{
var projectIdsForHierarchy = workspace.ProjectTracker.ImmutableProjects
var projectIdsForHierarchy = (workspace.DeferredState?.ProjectTracker.ImmutableProjects ?? ImmutableArray<AbstractProject>.Empty)
.Where(p => p.Language == LanguageNames.CSharp || p.Language == LanguageNames.VisualBasic)
.Where(p => p.Hierarchy == projectHierarchyOpt)
.Select(p => workspace.CurrentSolution.GetProject(p.Id).Id)
......
......@@ -25,6 +25,7 @@
using Microsoft.VisualStudio.Shell.Interop;
using NuGet.VisualStudio;
using Roslyn.Utilities;
using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
{
......@@ -42,6 +43,7 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP
{
private readonly object _gate = new object();
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly SVsServiceProvider _serviceProvider;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
// We refer to the package services through proxy types so that we can
......@@ -62,12 +64,14 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP
[ImportingConstructor]
public PackageInstallerService(
VisualStudioWorkspaceImpl workspace,
SVsServiceProvider serviceProvider,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService)
: base(workspace, SymbolSearchOptions.Enabled,
SymbolSearchOptions.SuggestForTypesInReferenceAssemblies,
SymbolSearchOptions.SuggestForTypesInNuGetPackages)
{
_workspace = workspace;
_serviceProvider = serviceProvider;
_editorAdaptersFactoryService = editorAdaptersFactoryService;
}
......@@ -80,7 +84,7 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP
protected override void EnableService()
{
// Our service has been enabled. Now load the VS package dlls.
var componentModel = _workspace.GetVsService<SComponentModel, IComponentModel>();
var componentModel = (IComponentModel)_serviceProvider.GetService(typeof(SComponentModel));
var packageInstallerServices = componentModel.GetExtensions<IVsPackageInstallerServices>().FirstOrDefault();
var packageInstaller = componentModel.GetExtensions<IVsPackageInstaller>().FirstOrDefault();
......@@ -150,7 +154,7 @@ private void OnSourceProviderSourcesChanged(object sender, EventArgs e)
if (workspace == _workspace && _workspace != null && _packageServices != null)
{
var projectId = documentId.ProjectId;
var dte = _workspace.GetVsService<SDTE, EnvDTE.DTE>();
var dte = (EnvDTE.DTE)_serviceProvider.GetService(typeof(SDTE));
var dteProject = _workspace.TryGetDTEProject(projectId);
if (dteProject != null)
{
......@@ -494,7 +498,7 @@ public void ShowManagePackagesDialog(string packageName)
{
this.AssertIsForeground();
var shell = _workspace.GetVsService<SVsShell, IVsShell>();
var shell = (IVsShell)_serviceProvider.GetService(typeof(SVsShell));
if (shell == null)
{
return;
......@@ -612,4 +616,4 @@ public void UninstallPackage(EnvDTE.Project project, string packageId, bool remo
}
}
}
}
\ No newline at end of file
}
......@@ -117,6 +117,7 @@
<Compile Include="Implementation\Extensions\VisualStudioWorkspaceImplExtensions.cs" />
<Compile Include="Implementation\Options\LanguageSettingsPersister.cs" />
<Compile Include="Implementation\ProjectSystem\Interop\IVsUndoState.cs" />
<Compile Include="Implementation\ProjectSystem\VisualStudioWorkspaceImpl.DeferredInitialization.cs" />
<Compile Include="Implementation\Remote\RemoteHostClientServiceFactory.cs" />
<Compile Include="Implementation\Remote\RemoteHostClientServiceFactory.RemoteHostClientService.cs" />
<Compile Include="Implementation\Remote\RemoteHostClientServiceFactory.SolutionChecksumUpdater.cs" />
......
......@@ -17,7 +17,7 @@ public bool IsSupported(Workspace workspace)
public string GetStorageLocation(Solution solution)
{
var vsWorkspace = solution.Workspace as VisualStudioWorkspaceImpl;
return vsWorkspace?.ProjectTracker.GetWorkingFolderPath(solution);
return vsWorkspace?.DeferredState?.ProjectTracker.GetWorkingFolderPath(solution);
}
}
}
\ No newline at end of file
......@@ -542,7 +542,7 @@ public void Rename(ISymbol symbol, string newName, Solution solution)
// Save the node keys.
var nodeKeyValidation = new NodeKeyValidation();
foreach (var project in workspace.ProjectTracker.ImmutableProjects)
foreach (var project in workspace.DeferredState.ProjectTracker.ImmutableProjects)
{
nodeKeyValidation.AddProject(project);
}
......
......@@ -70,7 +70,7 @@ public void RemoveDocument(DocumentId documentId)
public void FireEvents(DocumentId documentId, CancellationToken cancellationToken)
{
var project = _workspace.ProjectTracker.GetProject(documentId.ProjectId);
var project = _workspace.DeferredState.ProjectTracker.GetProject(documentId.ProjectId);
if (project == null)
{
return;
......
......@@ -138,7 +138,7 @@ private bool TryGetDocumentId(out DocumentId documentId)
return false;
}
var project = ((VisualStudioWorkspaceImpl)this.State.Workspace).ProjectTracker.GetProject(_incomingProjectId);
var project = ((VisualStudioWorkspaceImpl)this.State.Workspace).DeferredState?.ProjectTracker.GetProject(_incomingProjectId);
if (project == null)
{
return false;
......@@ -415,7 +415,7 @@ internal ProjectId GetProjectId()
internal AbstractProject GetAbstractProject()
{
return ((VisualStudioWorkspaceImpl)Workspace).ProjectTracker.GetProject(GetProjectId());
return ((VisualStudioWorkspaceImpl)Workspace).DeferredState.ProjectTracker.GetProject(GetProjectId());
}
internal SyntaxNode LookupNode(SyntaxNodeKey nodeKey)
......
......@@ -82,7 +82,7 @@ private Compilation GetCompilation()
vsProjectItems.AddFromFile(absoluteFilePath);
}
var hostProject = ((VisualStudioWorkspaceImpl)Workspace).ProjectTracker.GetProject(_projectId);
var hostProject = ((VisualStudioWorkspaceImpl)Workspace).DeferredState.ProjectTracker.GetProject(_projectId);
var projectCodeModel = ((IProjectCodeModelProvider)hostProject).ProjectCodeModel;
return projectCodeModel.GetOrCreateFileCodeModel(absoluteFilePath);
......
......@@ -61,7 +61,7 @@ internal static CPSProject CreateCPSProject(VisualStudioProjectTracker projectTr
var vsHierarchy = hierarchy as IVsHierarchy;
Func<ProjectId, IVsReportExternalErrors> getExternalErrorReporter = id => GetExternalErrorReporter(id, languageName);
return new CPSProject(_visualStudioWorkspace.ProjectTracker, getExternalErrorReporter, projectDisplayName, projectFilePath,
return new CPSProject(_visualStudioWorkspace.GetProjectTrackerAndInitializeIfNecessary(ServiceProvider.GlobalProvider), getExternalErrorReporter, projectDisplayName, projectFilePath,
vsHierarchy, languageName, projectGuid, binOutputPath, _serviceProvider, _visualStudioWorkspace, _hostDiagnosticUpdateSource,
commandLineParserServiceOpt: _visualStudioWorkspace.Services.GetLanguageServices(languageName)?.GetService<ICommandLineParserService>());
}
......@@ -80,7 +80,7 @@ internal static CPSProject CreateCPSProject(VisualStudioProjectTracker projectTr
var vsHierarchy = hierarchy as IVsHierarchy;
Func<ProjectId, IVsReportExternalErrors> getExternalErrorReporter = id => errorReporter;
return new CPSProject(_visualStudioWorkspace.ProjectTracker, getExternalErrorReporter, projectDisplayName, projectFilePath,
return new CPSProject(_visualStudioWorkspace.GetProjectTrackerAndInitializeIfNecessary(ServiceProvider.GlobalProvider), getExternalErrorReporter, projectDisplayName, projectFilePath,
vsHierarchy, languageName, projectGuid, binOutputPath, _serviceProvider, _visualStudioWorkspace, _hostDiagnosticUpdateSource,
commandLineParserServiceOpt: _visualStudioWorkspace.Services.GetLanguageServices(languageName)?.GetService<ICommandLineParserService>());
}
......
......@@ -14,6 +14,8 @@
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
......@@ -34,20 +36,13 @@ internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
[ImportingConstructor]
private RoslynVisualStudioWorkspace(
SVsServiceProvider serviceProvider,
SaveEventsService saveEventsService,
ExportProvider exportProvider,
[ImportMany] IEnumerable<Lazy<INavigableItemsPresenter>> navigableItemsPresenters,
[ImportMany] IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> referencedSymbolsPresenters,
[ImportMany] IEnumerable<Lazy<INavigableDefinitionProvider>> externalDefinitionProviders,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories)
: base(
serviceProvider,
backgroundWork: WorkspaceBackgroundWork.ParseAndCompile)
: base(exportProvider.AsExportProvider())
{
PrimaryWorkspace.Register(this);
InitializeStandardVisualStudioWorkspace(serviceProvider, saveEventsService);
_navigableItemsPresenters = navigableItemsPresenters;
_referencedSymbolsPresenters = referencedSymbolsPresenters;
_externalDefinitionProviders = externalDefinitionProviders;
......@@ -65,7 +60,13 @@ public override EnvDTE.FileCodeModel GetFileCodeModel(DocumentId documentId)
throw new ArgumentNullException(nameof(documentId));
}
var project = ProjectTracker.GetProject(documentId.ProjectId);
if (DeferredState == null)
{
// We haven't gotten any projects added yet, so we don't know where this came from
throw new ArgumentException(ServicesVSResources.The_given_DocumentId_did_not_come_from_the_Visual_Studio_workspace, nameof(documentId));
}
var project = DeferredState.ProjectTracker.GetProject(documentId.ProjectId);
if (project == null)
{
throw new ArgumentException(ServicesVSResources.The_given_DocumentId_did_not_come_from_the_Visual_Studio_workspace, nameof(documentId));
......@@ -97,7 +98,7 @@ internal override bool RenameFileCodeModelInstance(DocumentId documentId, string
return false;
}
var project = ProjectTracker.GetProject(documentId.ProjectId);
var project = DeferredState.ProjectTracker.GetProject(documentId.ProjectId);
if (project == null)
{
return false;
......@@ -153,7 +154,7 @@ internal override IInvisibleEditor OpenInvisibleEditor(IVisualStudioHostDocument
}
}
return new InvisibleEditor(ServiceProvider, hostDocument.FilePath, needsSave, needsUndoDisabled);
return new InvisibleEditor(DeferredState.ServiceProvider, hostDocument.FilePath, needsSave, needsUndoDisabled);
}
private static bool TryResolveSymbol(ISymbol symbol, Project project, CancellationToken cancellationToken, out ISymbol resolvedSymbol, out Project resolvedProject)
......
{
"dependencies": {
"Roslyn.Microsoft.Build": "0.0.2",
"Microsoft.VisualStudio.Composition": "14.2.19-pre",
"Microsoft.VisualStudio.Shell.14.0": "14.3.25407",
"Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime": "14.3.25407",
"RoslynDependencies.Microsoft.VisualStudio.ComponentModelHost": {
......@@ -27,4 +28,4 @@
"frameworks": {
"net46": { }
}
}
\ No newline at end of file
}
......@@ -65,7 +65,7 @@ private async Task RegisterPrimarySolutionAsync()
WellKnownRemoteHostServices.RemoteHostService_PersistentStorageService_UpdateSolutionIdStorageLocation,
solutionId.Id.ToByteArray(),
solutionId.DebugName,
_workspace.ProjectTracker.GetWorkingFolderPath(_workspace.CurrentSolution)).ConfigureAwait(false);
_workspace.DeferredState?.ProjectTracker.GetWorkingFolderPath(_workspace.CurrentSolution)).ConfigureAwait(false);
}
}
......
......@@ -59,7 +59,7 @@ private static void RegisterWorkspaceHost(Workspace workspace, RemoteHostClient
return;
}
vsWorkspace.ProjectTracker.RegisterWorkspaceHost(
vsWorkspace.DeferredState.ProjectTracker.RegisterWorkspaceHost(
new WorkspaceHost(vsWorkspace, client));
}
......
......@@ -188,9 +188,13 @@ private ImmutableHashSet<string> GetAnalyzersWithLoadErrors()
var vsWorkspace = _analyzersFolder.Workspace as VisualStudioWorkspaceImpl;
if (vsWorkspace != null)
{
var vsProject = vsWorkspace.ProjectTracker.GetProject(_analyzersFolder.ProjectId);
var vsProject = vsWorkspace.DeferredState?.ProjectTracker.GetProject(_analyzersFolder.ProjectId);
var vsAnalyzersMap = vsProject?.GetProjectAnalyzersMap();
return vsAnalyzersMap.Where(kvp => kvp.Value.HasLoadErrors).Select(kvp => kvp.Key).ToImmutableHashSet();
if (vsAnalyzersMap != null)
{
return vsAnalyzersMap.Where(kvp => kvp.Value.HasLoadErrors).Select(kvp => kvp.Key).ToImmutableHashSet();
}
}
return ImmutableHashSet<string>.Empty;
......
......@@ -22,7 +22,13 @@ public HierarchyItemToProjectIdMap(VisualStudioWorkspaceImpl workspace)
public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, out ProjectId projectId)
{
var project = _workspace.ProjectTracker.ImmutableProjects
if (_workspace.DeferredState == null)
{
projectId = default(ProjectId);
return false;
}
var project = _workspace.DeferredState.ProjectTracker.ImmutableProjects
.Where(p => p.Hierarchy == hierarchyItem.HierarchyIdentity.NestedHierarchy)
.Where(p => p.ProjectSystemName == hierarchyItem.CanonicalName)
.SingleOrDefault();
......
......@@ -23,10 +23,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
Public Function CreateProject(wszName As String, punkProject As Object, pProjHier As IVsHierarchy, pVbCompilerHost As IVbCompilerHost) As IVbCompilerProject Implements IVbCompiler.CreateProject
Dim hostDiagnosticUpdateSource = ComponentModel.GetService(Of HostDiagnosticUpdateSource)()
Workspace.ProjectTracker.TryDisconnectExistingDeferredProject(pProjHier, wszName)
Dim projectTracker = Workspace.GetProjectTrackerAndInitializeIfNecessary(Me)
projectTracker.TryDisconnectExistingDeferredProject(pProjHier, wszName)
Return New VisualBasicProjectShimWithServices(
Workspace.ProjectTracker,
projectTracker,
pVbCompilerHost,
wszName,
pProjHier,
......
......@@ -105,7 +105,11 @@ public void VsTextViewCreated(IVsTextView vsTextView)
AbstractProject project = GetXamlProject(hierarchy);
if (project == null)
{
project = new XamlProject(_vsWorkspace.ProjectTracker, hierarchy, _serviceProvider, _vsWorkspace);
project = new XamlProject(
_vsWorkspace.GetProjectTrackerAndInitializeIfNecessary(_serviceProvider),
hierarchy,
_serviceProvider,
_vsWorkspace);
}
IVisualStudioHostDocument vsDocument = project.GetCurrentDocumentFromPath(filePath);
......@@ -136,12 +140,15 @@ private void AttachRunningDocTableEvents()
private AbstractProject GetXamlProject(IVsHierarchy hierarchy)
{
return _vsWorkspace.ProjectTracker.ImmutableProjects.FirstOrDefault(p => p.Language == StringConstants.XamlLanguageName && p.Hierarchy == hierarchy);
var projects = _vsWorkspace.DeferredState?.ProjectTracker.ImmutableProjects ?? ImmutableArray<AbstractProject>.Empty;
return projects.FirstOrDefault(p => p.Language == StringConstants.XamlLanguageName && p.Hierarchy == hierarchy);
}
private bool TryCreateXamlDocument(AbstractProject project, string filePath, out IVisualStudioHostDocument vsDocument)
{
vsDocument = _vsWorkspace.ProjectTracker.DocumentProvider.TryGetDocumentForFile(
// We already have an AbstractProject, so the workspace has been created
vsDocument = _vsWorkspace.DeferredState.ProjectTracker.DocumentProvider.TryGetDocumentForFile(
project, filePath, SourceCodeKind.Regular,
tb => tb.ContentType.IsOfType(ContentTypeNames.XamlContentType),
_ => SpecializedCollections.EmptyReadOnlyList<string>());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册