提交 b173bfbe 编写于 作者: J Jonathon Marolf 提交者: GitHub

Merge pull request #16922 from vslsnap/merge-master-into-post-dev15-20170203-100201

Merge master into post-dev15
......@@ -6,7 +6,7 @@
<ManagedEsentVersion>1.9.4</ManagedEsentVersion>
<MicroBuildCoreVersion>0.2.0</MicroBuildCoreVersion>
<MicroBuildCoreSentinelVersion>1.0.0</MicroBuildCoreSentinelVersion>
<MicroBuildPluginsSwixBuildVersion>1.0.101</MicroBuildPluginsSwixBuildVersion>
<MicroBuildPluginsSwixBuildVersion>1.1.0-g0701ee829f</MicroBuildPluginsSwixBuildVersion>
<MicrosoftBuildVersion>15.1.0-preview-000458-02</MicrosoftBuildVersion>
<MicrosoftBuild14Version>14.3.0</MicrosoftBuild14Version>
<MicrosoftBuildFrameworkVersion>15.1.0-preview-000458-02</MicrosoftBuildFrameworkVersion>
......@@ -29,6 +29,7 @@
<MicrosoftVisualStudioDebuggerMetadataVersion>15.0.25824-RC</MicrosoftVisualStudioDebuggerMetadataVersion>
<MicrosoftVisualStudioInteractiveWindowVersion>2.0.0-rc3-61304-01</MicrosoftVisualStudioInteractiveWindowVersion>
<MicrosoftVisualStudioVsInteractiveWindowVersion>2.0.0-rc3-61304-01</MicrosoftVisualStudioVsInteractiveWindowVersion>
<MicrosoftVSSDKBuildToolsVersion>15.0.26124-RC3</MicrosoftVSSDKBuildToolsVersion>
<RoslynToolsMicrosoftLocateVSVersion>0.2.4-beta</RoslynToolsMicrosoftLocateVSVersion>
<RoslynToolsMicrosoftSignToolVersion>0.3.0-beta</RoslynToolsMicrosoftSignToolVersion>
<RoslynToolsMicrosoftVSIXExpInstallerVersion>0.2.4-beta</RoslynToolsMicrosoftVSIXExpInstallerVersion>
......
......@@ -73,7 +73,7 @@
<IsDev15RC Condition="Exists('$(MSBuildBinPath)\..\..\..\Common7\IDE\Microsoft.VisualStudio.ExtensionEngine.dll')">true</IsDev15RC>
<IsDev15RC Condition="Exists('$(MSBuildBinPath)\..\..\..\..\Common7\IDE\Microsoft.VisualStudio.ExtensionEngine.dll')">true</IsDev15RC>
<DeployExtension Condition="'$(IsDev15RC)' != 'true' OR '$(VisualStudioVersion)' != '15.0'">false</DeployExtension>
<VisualStudioBuildToolsVersion>15.0.25929-RC2</VisualStudioBuildToolsVersion>
<VisualStudioBuildToolsVersion>$(MicrosoftVSSDKBuildToolsVersion)</VisualStudioBuildToolsVersion>
<!-- For the moment our Dev14 VSI suites must continue to use the Dev14 SDK. -->
<VisualStudioBuildToolsVersion Condition="'$(IsDev14VsiBuild)' == 'true'">14.3.25420</VisualStudioBuildToolsVersion>
......
{
"dependencies": {
"Microsoft.VSSDK.BuildTools": "15.0.25929-RC2"
"Microsoft.VSSDK.BuildTools": "15.0.26124-RC3"
},
"frameworks": {
"net46": {}
}
}
}
\ No newline at end of file
......@@ -3,7 +3,7 @@
"Microsoft.Build.Logging.StructuredLogger": "1.0.58",
"MicroBuild.Core.Sentinel": "1.0.0",
"MicroBuild.Core": "0.2.0",
"MicroBuild.Plugins.SwixBuild": "1.0.101",
"MicroBuild.Plugins.SwixBuild": "1.1.0-g0701ee829f",
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.DiaSymReader.Native": "1.5.0-beta1",
"Microsoft.Net.Compilers": "2.0.0-rc2-61102-09",
......
{
"fixedPackages": {
"Microsoft.VSSDK.BuildTools": [ "14.3.25420", "15.0.25929-RC2" ],
"Microsoft.VSSDK.BuildTools": [ "14.3.25420" ],
"Newtonsoft.Json": "9.0.1",
"System.Reflection.Metadata": "1.0.21",
"System.Collections.Immutable": "1.1.36",
......@@ -39,7 +39,8 @@
"RoslynTools.*",
"^Microsoft.?Build.*",
"GitLink",
"Microsoft.NETCore.Runtime.CoreCLR"
"Microsoft.NETCore.Runtime.CoreCLR",
"Microsoft.VSSDK.BuildTools"
]
}
},
......
......@@ -1101,5 +1101,280 @@ static void Main(string[] args)
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(22, 43)
);
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseYieldReturnInAReturnByRefFunction()
{
var code = @"
class TestClass
{
int x = 0;
ref int TestFunction()
{
yield return x;
ref int localFunction()
{
yield return x;
}
yield return localFunction();
}
}";
CreateCompilationWithMscorlib(code).VerifyDiagnostics(
// (9,17): error CS8154: The body of 'localFunction()' cannot be an iterator block because 'localFunction()' returns by reference
// ref int localFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "localFunction").WithArguments("localFunction()").WithLocation(9, 17),
// (5,13): error CS8154: The body of 'TestClass.TestFunction()' cannot be an iterator block because 'TestClass.TestFunction()' returns by reference
// ref int TestFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "TestFunction").WithArguments("TestClass.TestFunction()").WithLocation(5, 13));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseRefReturnInExpressionTree_ParenthesizedLambdaExpression()
{
var code = @"
using System.Linq.Expressions;
class TestClass
{
int x = 0;
delegate ref int RefReturnIntDelegate(int y);
void TestFunction()
{
Expression<RefReturnIntDelegate> lambda = (y) => ref x;
}
}";
CreateCompilationWithMscorlibAndSystemCore(code).VerifyDiagnostics(
// (11,51): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<RefReturnIntDelegate> lambda = (y) => ref x;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(y) => ref x").WithLocation(11, 51));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseRefReturnInExpressionTree_SimpleLambdaExpression()
{
var code = @"
using System.Linq.Expressions;
class TestClass
{
int x = 0;
delegate ref int RefReturnIntDelegate(int y);
void TestFunction()
{
Expression<RefReturnIntDelegate> lambda = y => ref x;
}
}";
CreateCompilationWithMscorlibAndSystemCore(code).VerifyDiagnostics(
// (11,51): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<RefReturnIntDelegate> lambda = y => ref x;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "y => ref x").WithLocation(11, 51));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotCallExpressionThatReturnsByRefInExpressionTree()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace TestRefReturns
{
class TestClass
{
int x = 0;
ref int RefReturnFunction()
{
return ref x;
}
ref int RefReturnProperty
{
get { return ref x; }
}
ref int this[int y]
{
get { return ref x; }
}
int TakeRefFunction(ref int y)
{
return y;
}
void TestFunction()
{
Expression<Func<int>> lambda1 = () => TakeRefFunction(ref RefReturnFunction());
Expression<Func<int>> lambda2 = () => TakeRefFunction(ref RefReturnProperty);
Expression<Func<int>> lambda3 = () => TakeRefFunction(ref this[0]);
}
}
}";
CreateCompilationWithMscorlibAndSystemCore(code).VerifyDiagnostics(
// (32,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda1 = () => TakeRefFunction(ref RefReturnFunction());
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "RefReturnFunction()").WithLocation(32, 71),
// (33,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda2 = () => TakeRefFunction(ref RefReturnProperty);
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "RefReturnProperty").WithLocation(33, 71),
// (34,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda3 = () => TakeRefFunction(ref this[0]);
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "this[0]").WithLocation(34, 71));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotRefReturnQueryRangeVariable()
{
var code = @"
using System.Linq;
class TestClass
{
delegate ref char RefCharDelegate();
void TestMethod()
{
var x = from c in ""TestValue"" select (RefCharDelegate)(() => ref c);
}
}";
CreateCompilationWithMscorlibAndSystemCore(code).VerifyDiagnostics(
// (8,74): error CS8159: Cannot return the range variable 'c' by reference
// var x = from c in "TestValue" select (RefCharDelegate)(() => ref c);
Diagnostic(ErrorCode.ERR_RefReturnRangeVariable, "c").WithArguments("c").WithLocation(8, 74));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotAssignRefInNonIdentityConversion()
{
var code = @"
using System;
using System.Collections.Generic;
class TestClass
{
int intVar = 0;
string stringVar = ""TEST"";
void TestMethod()
{
ref int? nullableConversion = ref intVar;
ref dynamic dynamicConversion = ref intVar;
ref IEnumerable<char> enumerableConversion = ref stringVar;
ref IFormattable interpolatedStringConversion = ref stringVar;
}
}";
CreateCompilationWithMscorlib(code).VerifyDiagnostics(
// (12,43): error CS8173: The expression must be of type 'int?' because it is being assigned by reference
// ref int? nullableConversion = ref intVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "intVar").WithArguments("int?").WithLocation(12, 43),
// (13,45): error CS8173: The expression must be of type 'dynamic' because it is being assigned by reference
// ref dynamic dynamicConversion = ref intVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "intVar").WithArguments("dynamic").WithLocation(13, 45),
// (14,58): error CS8173: The expression must be of type 'IEnumerable<char>' because it is being assigned by reference
// ref IEnumerable<char> enumerableConversion = ref stringVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "stringVar").WithArguments("System.Collections.Generic.IEnumerable<char>").WithLocation(14, 58),
// (15,61): error CS8173: The expression must be of type 'IFormattable' because it is being assigned by reference
// ref IFormattable interpolatedStringConversion = ref stringVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "stringVar").WithArguments("System.IFormattable").WithLocation(15, 61));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void IteratorMethodsCannotHaveRefLocals()
{
var code = @"
using System.Collections.Generic;
class TestClass
{
int x = 0;
IEnumerable<int> TestMethod()
{
ref int y = ref x;
yield return y;
IEnumerable<int> localFunction()
{
ref int z = ref x;
yield return z;
}
foreach(var item in localFunction())
{
yield return item;
}
}
}";
CreateCompilationWithMscorlib(code).VerifyDiagnostics(
// (13,21): error CS8176: Iterators cannot have by reference locals
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "z").WithLocation(13, 21),
// (8,17): error CS8176: Iterators cannot have by reference locals
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "y").WithLocation(8, 17));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void AsyncMethodsCannotHaveRefLocals()
{
var code = @"
using System.Threading.Tasks;
class TestClass
{
int x = 0;
async Task TestMethod()
{
ref int y = ref x;
await Task.Run(async () =>
{
ref int z = ref x;
await Task.Delay(0);
});
}
}";
CreateCompilationWithMscorlib45(code).VerifyDiagnostics(
// (8,17): error CS8177: Async methods cannot have by reference locals
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y = ref x").WithLocation(8, 17),
// (11,21): error CS8177: Async methods cannot have by reference locals
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "z = ref x").WithLocation(11, 21));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseAwaitExpressionInACallToAFunctionThatReturnsByRef()
{
var code = @"
using System;
using System.Threading.Tasks;
class TestClass
{
int x = 0;
ref int Save(int y)
{
x = y;
return ref x;
}
void Write(ref int y)
{
Console.WriteLine(y);
}
async Task TestMethod()
{
Write(ref Save(await Task.FromResult(0)));
}
}";
CreateCompilationWithMscorlib45(code).VerifyEmitDiagnostics(
// (18,24): error CS8178: 'await' cannot be used in an expression containing a call to 'TestClass.Save(int)' because it returns by reference
// Write(ref Save(await Task.FromResult(0)));
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "await Task.FromResult(0)").WithArguments("TestClass.Save(int)").WithLocation(18, 24));
}
}
}
......@@ -624,7 +624,7 @@
<Compile Include="Implementation\Workspaces\ProjectCacheServiceFactory.cs" />
<Compile Include="Implementation\Workspaces\EditorTextFactoryService.cs" />
<Compile Include="Implementation\Workspaces\TextUndoHistoryWorkspaceServiceFactoryService.cs" />
<Compile Include="Implementation\Workspaces\WorkspaceTaskSchedulerFactoryFactory.cs" />
<Compile Include="Implementation\Workspaces\EditorTaskSchedulerFactory.cs" />
<Compile Include="IRefactorNotifyService.cs" />
<Compile Include="Tags\IImageMonikerService.cs" />
<Compile Include="Tags\DefaultImageMonikerService.cs" />
......
......@@ -432,7 +432,7 @@ private async Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project p
this.AssertIsForeground();
return fix.Action.IsApplicable(document.Project.Solution.Workspace);
},
cancellationToken, TaskCreationOptions.None, this.ForegroundTaskScheduler).ConfigureAwait(false);
cancellationToken, TaskCreationOptions.None, ForegroundTaskScheduler).ConfigureAwait(false);
this.AssertIsBackground();
if (applicable)
......
......@@ -34,8 +34,6 @@ public ForegroundNotificationService()
_workQueue = new PriorityQueue();
_lastProcessedTimeInMS = Environment.TickCount;
Contract.ThrowIfFalse(IsValid());
Debug.Assert(IsForeground());
Task.Factory.SafeStartNewFromAsync(ProcessAsync, CancellationToken.None, TaskScheduler.Default);
}
......
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Editor.Commands;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion
{
......@@ -81,7 +82,7 @@ private void CommitUniqueCompletionListItemAsynchronously()
// Nothing happened between when we were invoked and now.
CommitIfUnique(t.Result);
}
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.ForegroundTaskScheduler);
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ForegroundTaskScheduler);
task.CompletesAsyncOperation(token);
}
......
......@@ -145,7 +145,7 @@ private void StartSelectedItemUpdateTask(int delay, bool updateUIWhenDone)
t => PushSelectedItemsToPresenter(t.Result),
cancellationToken,
TaskContinuationOptions.OnlyOnRanToCompletion,
ForegroundThreadAffinitizedObject.CurrentForegroundThreadData.TaskScheduler).CompletesAsyncOperation(asyncToken);
ForegroundTaskScheduler).CompletesAsyncOperation(asyncToken);
}
}
......
......@@ -10,41 +10,25 @@
namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces
{
[ExportWorkspaceServiceFactory(typeof(IWorkspaceTaskSchedulerFactory), ServiceLayer.Editor), Shared]
internal class WorkspaceTaskSchedulerFactoryFactory : IWorkspaceServiceFactory
[ExportWorkspaceService(typeof(IWorkspaceTaskSchedulerFactory), ServiceLayer.Editor), Shared]
internal class EditorTaskSchedulerFactory : WorkspaceTaskSchedulerFactory
{
private readonly Service _singleton;
private readonly IAsynchronousOperationListener _aggregateListener;
[ImportingConstructor]
public WorkspaceTaskSchedulerFactoryFactory(
[ImportMany]IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners)
public EditorTaskSchedulerFactory([ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners)
{
_singleton = new Service(new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.Workspace));
_aggregateListener = new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.Workspace);
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
protected override object BeginAsyncOperation(string taskName)
{
return _singleton;
return _aggregateListener.BeginAsyncOperation(taskName);
}
private class Service : WorkspaceTaskSchedulerFactory
protected override void CompleteAsyncOperation(object asyncToken, Task task)
{
private readonly IAsynchronousOperationListener _aggregateListener;
public Service(IAsynchronousOperationListener aggregateListener)
{
_aggregateListener = aggregateListener;
}
protected override object BeginAsyncOperation(string taskName)
{
return _aggregateListener.BeginAsyncOperation(taskName);
}
protected override void CompleteAsyncOperation(object asyncToken, Task task)
{
task.CompletesAsyncOperation((IAsyncToken)asyncToken);
}
task.CompletesAsyncOperation((IAsyncToken)asyncToken);
}
}
}
......@@ -50,7 +50,7 @@ internal class ForegroundThreadAffinitizedObject
{
private static readonly ForegroundThreadData s_fallbackForegroundThreadData;
private static ForegroundThreadData s_currentForegroundThreadData;
private readonly ForegroundThreadData _foregroundThreadData;
private readonly ForegroundThreadData _foregroundThreadDataWhenCreated;
internal static ForegroundThreadData CurrentForegroundThreadData
{
......@@ -66,19 +66,14 @@ internal static ForegroundThreadData CurrentForegroundThreadData
}
}
internal ForegroundThreadData ForegroundThreadData
{
get { return _foregroundThreadData; }
}
internal Thread ForegroundThread
{
get { return _foregroundThreadData.Thread; }
get { return _foregroundThreadDataWhenCreated.Thread; }
}
internal TaskScheduler ForegroundTaskScheduler
{
get { return _foregroundThreadData.TaskScheduler; }
get { return _foregroundThreadDataWhenCreated.TaskScheduler; }
}
// HACK: This is a dangerous way of establishing the 'foreground' thread affinity of an
......@@ -90,12 +85,16 @@ static ForegroundThreadAffinitizedObject()
s_fallbackForegroundThreadData = ForegroundThreadData.CreateDefault(Unknown);
}
public ForegroundThreadAffinitizedObject(ForegroundThreadData foregroundThreadData = null, bool assertIsForeground = false)
public ForegroundThreadAffinitizedObject(bool assertIsForeground = false)
{
_foregroundThreadData = foregroundThreadData ?? CurrentForegroundThreadData;
_foregroundThreadDataWhenCreated = CurrentForegroundThreadData;
// For sanity's sake, ensure that our idea of "foreground" is the same as WPF's
Contract.ThrowIfFalse(Application.Current == null || Application.Current.Dispatcher.Thread == ForegroundThread);
// For sanity's sake, ensure that our idea of "foreground" is the same as WPF's. But we won't assert
// anything if we haven't figured it out yet.
Contract.ThrowIfFalse(
CurrentForegroundThreadData.Kind == ForegroundThreadDataKind.Unknown ||
Application.Current == null ||
Application.Current.Dispatcher.Thread == ForegroundThread);
// ForegroundThreadAffinitizedObject might not necessarily be created on a foreground thread.
// AssertIsForeground here only if the object must be created on a foreground thread.
......@@ -110,15 +109,6 @@ public bool IsForeground()
return Thread.CurrentThread == ForegroundThread;
}
/// <summary>
/// Ensure this is a supported scheduling context like Wpf or explicit STA scheduler.
/// </summary>
/// <returns></returns>
public bool IsValid()
{
return _foregroundThreadData.Kind != Unknown;
}
public void AssertIsForeground()
{
Contract.ThrowIfFalse(IsForeground());
......
......@@ -24,8 +24,8 @@ public static Type[] GetLanguageNeutralTypes()
var types = new[]
{
// ROSLYN
typeof(Microsoft.CodeAnalysis.Editor.Implementation.Workspaces.WorkspaceTaskSchedulerFactoryFactory),
typeof(Microsoft.CodeAnalysis.Host.WorkspaceTaskSchedulerFactoryFactory),
typeof(Microsoft.CodeAnalysis.Editor.Implementation.Workspaces.EditorTaskSchedulerFactory),
typeof(Microsoft.CodeAnalysis.Host.WorkspaceTaskSchedulerFactory),
typeof(Microsoft.CodeAnalysis.Formatting.Rules.DefaultFormattingRuleFactoryServiceFactory),
typeof(Microsoft.CodeAnalysis.Host.PersistentStorageServiceFactory),
typeof(Microsoft.CodeAnalysis.Text.Implementation.TextBufferFactoryService.TextBufferCloneServiceFactory),
......
......@@ -54,6 +54,7 @@ public StaTaskScheduler(int numberOfThreads)
}
}
});
thread.Name = $"{nameof(StaTaskScheduler)} thread";
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
return thread;
......
......@@ -14,7 +14,6 @@ internal class BackgroundCompiler : IDisposable
{
private Workspace _workspace;
private readonly IWorkspaceTaskScheduler _compilationScheduler;
private readonly IWorkspaceTaskScheduler _notificationQueue;
// Used to keep a strong reference to the built compilations so they are not GC'd
private Compilation[] _mostRecentCompilations;
......@@ -28,10 +27,8 @@ public BackgroundCompiler(Workspace workspace)
// make a scheduler that runs on the thread pool
var taskSchedulerFactory = workspace.Services.GetService<IWorkspaceTaskSchedulerFactory>();
_compilationScheduler = taskSchedulerFactory.CreateTaskScheduler(TaskScheduler.Default);
_compilationScheduler = taskSchedulerFactory.CreateBackgroundTaskScheduler();
// default uses current (ideally UI/foreground scheduler) if possible
_notificationQueue = taskSchedulerFactory.CreateTaskQueue();
_cancellationSource = new CancellationTokenSource();
_workspace.WorkspaceChanged += this.OnWorkspaceChanged;
_workspace.DocumentOpened += OnDocumentOpened;
......
......@@ -25,7 +25,7 @@ public BackgroundParser(Workspace workspace)
_workspace = workspace;
var taskSchedulerFactory = workspace.Services.GetService<IWorkspaceTaskSchedulerFactory>();
_taskScheduler = taskSchedulerFactory.CreateTaskScheduler(TaskScheduler.Default);
_taskScheduler = taskSchedulerFactory.CreateBackgroundTaskScheduler();
_workspace.WorkspaceChanged += this.OnWorkspaceChanged;
var editorWorkspace = workspace as Workspace;
......
......@@ -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();
......
......@@ -140,7 +140,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));
......
......@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics
......@@ -34,15 +35,18 @@ internal partial class VisualStudioWorkspaceDiagnosticAnalyzerProviderService :
private static readonly AnalyzerAssemblyLoader s_analyzerAssemblyLoader = new AnalyzerAssemblyLoader();
[ImportingConstructor]
public VisualStudioWorkspaceDiagnosticAnalyzerProviderService(VisualStudioWorkspaceImpl workspace)
public VisualStudioWorkspaceDiagnosticAnalyzerProviderService(
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider)
{
var dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
// Microsoft.VisualStudio.ExtensionManager is non-versioned, so we need to dynamically load it, depending on the version of VS we are running on
// this will allow us to build once and deploy on different versions of VS SxS.
var vsDteVersion = Version.Parse(workspace.GetVsDte().Version.Split(' ')[0]); // DTE.Version is in the format of D[D[.D[D]]][ (?+)], so we need to split out the version part and check for uninitialized Major/Minor below
var vsDteVersion = Version.Parse(dte.Version.Split(' ')[0]); // DTE.Version is in the format of D[D[.D[D]]][ (?+)], so we need to split out the version part and check for uninitialized Major/Minor below
var assembly = Assembly.Load($"Microsoft.VisualStudio.ExtensionManager, Version={(vsDteVersion.Major == -1 ? 0 : vsDteVersion.Major)}.{(vsDteVersion.Minor == -1 ? 0 : vsDteVersion.Minor)}.0.0, PublicKeyToken=b03f5f7f11d50a3a");
// Get the analyzer assets for installed VSIX extensions through the VSIX extension manager.
var extensionManager = workspace.GetVsService(assembly.GetType("Microsoft.VisualStudio.ExtensionManager.SVsExtensionManager"));
var extensionManager = serviceProvider.GetService(assembly.GetType("Microsoft.VisualStudio.ExtensionManager.SVsExtensionManager"));
if (extensionManager == null)
{
// extension manager can't be null. if it is null, then VS is seriously broken.
......
......@@ -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)
{
......
......@@ -62,7 +62,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();
......
......@@ -21,7 +21,7 @@ protected override void Initialize()
var defaultForegroundThreadData = ForegroundThreadData.CreateDefault(
defaultKind: ForegroundThreadDataKind.ForcedByPackageInitialize);
ForegroundThreadAffinitizedObject.CurrentForegroundThreadData = defaultForegroundThreadData;
ForegroundObject = new ForegroundThreadAffinitizedObject(defaultForegroundThreadData);
ForegroundObject = new ForegroundThreadAffinitizedObject();
}
protected void LoadComponentsInUIContextOnceSolutionFullyLoaded()
......
// 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,18 +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)
{
if (ErrorHandler.Succeeded(solution.GetUniqueUINameOfProject(hierarchy, out var 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>
......
......@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Design;
using Microsoft.VisualStudio.Shell.Interop;
......@@ -18,19 +19,29 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
[ExportWorkspaceServiceFactory(typeof(IFrameworkAssemblyPathResolver), ServiceLayer.Host), Shared]
internal sealed class VisualStudiorFrameworkAssemblyPathResolverFactory : IWorkspaceServiceFactory
{
private readonly IServiceProvider _serviceProvider;
[ImportingConstructor]
public VisualStudiorFrameworkAssemblyPathResolverFactory(SVsServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new Service(workspaceServices.Workspace as VisualStudioWorkspaceImpl);
return new Service(workspaceServices.Workspace as VisualStudioWorkspace, _serviceProvider);
}
private sealed class Service : ForegroundThreadAffinitizedObject, IFrameworkAssemblyPathResolver
{
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly VisualStudioWorkspace _workspace;
private readonly IServiceProvider _serviceProvider;
public Service(VisualStudioWorkspaceImpl workspace)
public Service(VisualStudioWorkspace workspace, IServiceProvider serviceProvider)
: base(assertIsForeground: false)
{
_workspace = workspace;
_serviceProvider = serviceProvider;
}
public string ResolveAssemblyPath(
......@@ -105,7 +116,8 @@ private Assembly ResolveAssembly(ProjectId projectId, string assemblyName)
return null;
}
if (!_workspace.TryGetHierarchy(projectId, out var hierarchy) ||
IVsHierarchy hierarchy = _workspace.GetHierarchy(projectId);
if (hierarchy == null ||
!hierarchy.TryGetProperty((__VSHPROPID)__VSHPROPID4.VSHPROPID_TargetFrameworkMoniker, out string targetMoniker) ||
targetMoniker == null)
{
......@@ -140,9 +152,9 @@ private Assembly ResolveAssembly(ProjectId projectId, string assemblyName)
try
{
var frameworkProvider = new VsTargetFrameworkProvider(
_workspace.GetVsService<SVsFrameworkMultiTargeting, IVsFrameworkMultiTargeting>(),
(IVsFrameworkMultiTargeting)_serviceProvider.GetService(typeof(SVsFrameworkMultiTargeting)),
targetMoniker,
_workspace.GetVsService<SVsSmartOpenScope, IVsSmartOpenScope>());
(IVsSmartOpenScope)_serviceProvider.GetService(typeof(SVsSmartOpenScope)));
return frameworkProvider.GetReflectionAssembly(new AssemblyName(assemblyName));
}
catch (InvalidOperationException)
......
......@@ -14,24 +14,25 @@ internal sealed class VsMetadataServiceFactory : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
var manager = workspaceServices.GetService<VisualStudioMetadataReferenceManager>();
Debug.Assert(manager != null);
return new Service(manager);
return new Service(workspaceServices);
}
private sealed class Service : IMetadataService
{
private readonly VisualStudioMetadataReferenceManager _manager;
private readonly Lazy<VisualStudioMetadataReferenceManager> _manager;
public Service(VisualStudioMetadataReferenceManager manager)
public Service(HostWorkspaceServices workspaceServices)
{
_manager = manager;
// We will defer creation of this reference manager until we have to to avoid it being constructed too
// early and potentially causing deadlocks. We do initialize it on the UI thread in the
// VisualStudioWorkspaceImpl.DeferredState constructor to ensure it gets created there.
_manager = new Lazy<VisualStudioMetadataReferenceManager>(
() => workspaceServices.GetRequiredService<VisualStudioMetadataReferenceManager>());
}
public PortableExecutableReference GetReference(string resolvedPath, MetadataReferenceProperties properties)
{
return _manager.CreateMetadataReferenceSnapshot(resolvedPath, properties);
return _manager.Value.CreateMetadataReferenceSnapshot(resolvedPath, properties);
}
}
}
......
......@@ -78,6 +78,11 @@ protected override void OnDocumentClosing(DocumentId documentId)
}
}
/// <summary>
/// Returns the hierarchy for a given project.
/// </summary>
/// <param name="projectId">The <see cref="ProjectId"/> for the project.</param>
/// <returns>The <see cref="IVsHierarchy"/>, or null if the project doesn't have one.</returns>
public abstract IVsHierarchy GetHierarchy(ProjectId projectId);
public abstract string GetFilePath(DocumentId documentId);
......
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Implementation.Workspaces;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
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 = (VisualStudioDocumentTrackingService)workspace.Services.GetService<IDocumentTrackingService>();
var documentProvider = new DocumentProvider(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();
VisualStudioProjectCacheHostServiceFactory.ConnectProjectCacheServiceToDocumentTracking(workspace.Services, (ProjectCacheService)workspace.CurrentSolution.Services.CacheService);
// 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)
{
if (ErrorHandler.Succeeded(solution.GetUniqueUINameOfProject(hierarchy, out string 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,60 @@ 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.
/// This is Lazy because it might be created on a background thread when nothing is initialized yet.
/// </summary>
private readonly Lazy<ForegroundThreadAffinitizedObject> _foregroundObject
= new Lazy<ForegroundThreadAffinitizedObject>(() => new ForegroundThreadAffinitizedObject());
// 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 = (VisualStudioDocumentTrackingService)this.Services.GetService<IDocumentTrackingService>();
var documentProvider = new DocumentProvider(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.Value.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>
internal VisualStudioProjectTracker ProjectTracker
{
get
{
return _projectTracker;
return GetProjectTrackerAndInitializeIfNecessary(ServiceProvider.GlobalProvider);
}
}
internal void ClearReferenceCache()
{
_projectTracker.MetadataReferenceProvider.ClearCache();
DeferredState?.ProjectTracker.MetadataReferenceProvider.ClearCache();
}
internal IVisualStudioHostDocument GetHostDocument(DocumentId documentId)
......@@ -131,7 +113,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 +147,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(),
......@@ -434,7 +416,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>();
......@@ -646,7 +628,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);
}
......@@ -720,28 +702,7 @@ public override void CloseAdditionalDocument(DocumentId documentId)
{
CloseDocumentCore(documentId);
}
public bool TryGetInfoBarData(out IVsWindowFrame frame, out IVsInfoBarUIFactory factory)
{
frame = null;
factory = null;
var monitorSelectionService = ServiceProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
// We want to get whichever window is currently in focus (including toolbars) as we could have had an exception thrown from the error list or interactive window
if (monitorSelectionService != null &&
ErrorHandler.Succeeded(monitorSelectionService.GetCurrentElementValue((uint)VSConstants.VSSELELEMID.SEID_WindowFrame, out var value)))
{
frame = value as IVsWindowFrame;
}
else
{
return false;
}
factory = ServiceProvider.GetService(typeof(SVsInfoBarUIFactory)) as IVsInfoBarUIFactory;
return frame != null && factory != null;
}
public void OpenDocumentCore(DocumentId documentId, bool activate = true)
{
if (documentId == null)
......@@ -749,7 +710,7 @@ public void OpenDocumentCore(DocumentId documentId, bool activate = true)
throw new ArgumentNullException(nameof(documentId));
}
if (!_foregroundObject.IsForeground())
if (!_foregroundObject.Value.IsForeground())
{
throw new InvalidOperationException(ServicesVSResources.This_workspace_only_supports_opening_documents_on_the_UI_thread);
}
......@@ -782,7 +743,7 @@ private bool TryGetFrame(IVisualStudioHostDocument document, out IVsWindowFrame
// document using its ItemId. Thus, we must use OpenDocumentViaProject, which only
// depends on the file path.
return ErrorHandler.Succeeded(_shellOpenDocument.OpenDocumentViaProject(
return ErrorHandler.Succeeded(DeferredState.ShellOpenDocumentService.OpenDocumentViaProject(
document.FilePath,
VSConstants.LOGVIEWID.TextView_guid,
out var oleServiceProvider,
......@@ -821,7 +782,7 @@ public void CloseDocumentCore(DocumentId documentId)
var document = this.GetHostDocument(documentId);
if (document != null)
{
if (ErrorHandler.Succeeded(_shellOpenDocument.IsDocumentOpen(null, 0, document.FilePath, Guid.Empty, 0, out var uiHierarchy, null, out var frame, out var isOpen)))
if (ErrorHandler.Succeeded(DeferredState.ShellOpenDocumentService.IsDocumentOpen(null, 0, document.FilePath, Guid.Empty, 0, out var uiHierarchy, null, out var frame, out var isOpen)))
{
// TODO: do we need save argument for CloseDocument?
frame.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave);
......@@ -897,7 +858,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;
......@@ -933,7 +894,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;
......@@ -987,7 +948,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)
{
......@@ -1066,7 +1027,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();
......@@ -1109,26 +1070,9 @@ 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;
}
public object GetVsService(Type serviceType)
{
return ServiceProvider.GetService(serviceType);
}
public DTE GetVsDte()
{
return GetVsService<SDTE, DTE>();
}
internal override bool CanAddProjectReference(ProjectId referencingProject, ProjectId referencedProject)
{
_foregroundObject.AssertIsForeground();
_foregroundObject.Value.AssertIsForeground();
if (!TryGetHierarchy(referencingProject, out var referencingHierarchy) ||
!TryGetHierarchy(referencedProject, out var referencedHierarchy))
{
......@@ -1188,7 +1132,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.
......@@ -1455,7 +1399,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)
......
// 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.ComponentModel;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
......@@ -22,14 +21,18 @@ internal class CommentTaskTokenSerializer : IOptionPersister
[ImportingConstructor]
public CommentTaskTokenSerializer(
VisualStudioWorkspaceImpl workspace)
VisualStudioWorkspace workspace,
[Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider)
{
_optionService = workspace.Services.GetService<IOptionService>();
_taskList = workspace.GetVsService<SVsTaskList, ITaskList>();
// The SVsTaskList may not be available or doesn't actually implement ITaskList
// in the "devenv /build" scenario
_taskList = serviceProvider.GetService(typeof(SVsTaskList)) as ITaskList;
// GetTaskTokenList is safe in the face of nulls
_lastCommentTokenCache = GetTaskTokenList(_taskList);
// The SVsTaskList may not be available (e.g. during "devenv /build")
if (_taskList != null)
{
_taskList.PropertyChanged += OnPropertyChanged;
......
......@@ -19,14 +19,14 @@ internal partial class VisualStudioErrorReportingService : IErrorReportingServic
private readonly static InfoBarButton s_enableItem = new InfoBarButton(ServicesVSResources.Enable);
private readonly static InfoBarButton s_enableAndIgnoreItem = new InfoBarButton(ServicesVSResources.Enable_and_ignore_future_errors);
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly IServiceProvider _serviceProvider;
private readonly IForegroundNotificationService _foregroundNotificationService;
private readonly IAsynchronousOperationListener _listener;
public VisualStudioErrorReportingService(
VisualStudioWorkspaceImpl workspace, IForegroundNotificationService foregroundNotificationService, IAsynchronousOperationListener listener)
SVsServiceProvider serviceProvider, IForegroundNotificationService foregroundNotificationService, IAsynchronousOperationListener listener)
{
_workspace = workspace;
_serviceProvider = serviceProvider;
_foregroundNotificationService = foregroundNotificationService;
_listener = listener;
}
......@@ -36,13 +36,34 @@ public void ShowErrorInfo(string message, params ErrorReportingUI[] items)
// We can be called from any thread since errors can occur anywhere, however we can only construct and InfoBar from the UI thread.
_foregroundNotificationService.RegisterNotification(() =>
{
if (_workspace.TryGetInfoBarData(out var frame, out var factory))
if (TryGetInfoBarData(out var frame, out var factory))
{
CreateInfoBar(factory, frame, message, items);
}
}, _listener.BeginAsyncOperation("Show InfoBar"));
}
private bool TryGetInfoBarData(out IVsWindowFrame frame, out IVsInfoBarUIFactory factory)
{
frame = null;
factory = null;
var monitorSelectionService = _serviceProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
// We want to get whichever window is currently in focus (including toolbars) as we could have had an exception thrown from the error list or interactive window
if (monitorSelectionService != null &&
ErrorHandler.Succeeded(monitorSelectionService.GetCurrentElementValue((uint)VSConstants.VSSELELEMID.SEID_WindowFrame, out object value)))
{
frame = value as IVsWindowFrame;
}
else
{
return false;
}
factory = _serviceProvider.GetService(typeof(SVsInfoBarUIFactory)) as IVsInfoBarUIFactory;
return frame != null && factory != null;
}
private void CreateInfoBar(IVsInfoBarUIFactory factory, IVsWindowFrame frame, string message, ErrorReportingUI[] items)
{
if (ErrorHandler.Failed(frame.GetProperty((int)__VSFPROPID7.VSFPROPID_InfoBarHost, out var unknown)))
......
......@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
......@@ -19,11 +20,11 @@ internal sealed class VisualStudioErrorReportingServiceFactory : IWorkspaceServi
[ImportingConstructor]
public VisualStudioErrorReportingServiceFactory(
VisualStudioWorkspaceImpl workspace,
SVsServiceProvider serviceProvider,
IForegroundNotificationService foregroundNotificationService,
[ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners)
{
_singleton = new VisualStudioErrorReportingService(workspace, foregroundNotificationService, new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.InfoBar));
_singleton = new VisualStudioErrorReportingService(serviceProvider, foregroundNotificationService, new AggregateAsynchronousOperationListener(asyncListeners, FeatureAttribute.InfoBar));
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
......
......@@ -48,8 +48,12 @@ private static IWorkspaceService GetMiscProjectCache(HostWorkspaceServices works
private static IWorkspaceService GetVisualStudioProjectCache(HostWorkspaceServices workspaceServices)
{
var projectCacheService = new ProjectCacheService(workspaceServices.Workspace, ImplicitCacheTimeoutInMS);
// We will finish setting this up in VisualStudioWorkspaceImpl.DeferredInitializationState
return new ProjectCacheService(workspaceServices.Workspace, ImplicitCacheTimeoutInMS);
}
internal static void ConnectProjectCacheServiceToDocumentTracking(HostWorkspaceServices workspaceServices, ProjectCacheService projectCacheService)
{
var documentTrackingService = workspaceServices.GetService<IDocumentTrackingService>();
// Subscribe to events so that we can cache items from the active document's project
......@@ -70,8 +74,6 @@ private static IWorkspaceService GetVisualStudioProjectCache(HostWorkspaceServic
manager.Clear();
}
};
return projectCacheService;
}
private class ActiveProjectCacheManager
......
// 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.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Editor.Implementation.Workspaces;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Utilities;
using Roslyn.Utilities;
using System.Threading;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
[ExportWorkspaceService(typeof(IWorkspaceTaskSchedulerFactory), ServiceLayer.Host), Shared]
internal class VisualStudioTaskSchedulerFactory : EditorTaskSchedulerFactory
{
[ImportingConstructor]
public VisualStudioTaskSchedulerFactory([ImportMany] IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> asyncListeners)
: base(asyncListeners)
{
}
public override IWorkspaceTaskScheduler CreateEventingTaskQueue()
{
// When we are creating the workspace, we might not actually have established what the UI thread is, since
// we might be getting created via MEF. So we'll allow the queue to be created now, and once we actually need
// to queue something we'll then start using the task queue from there.
// In Visual Studio, we raise these events on the UI thread. At this point we should know
// exactly which thread that is.
return new VisualStudioTaskScheduler(this);
}
private class VisualStudioTaskScheduler : IWorkspaceTaskScheduler
{
private readonly Lazy<WorkspaceTaskQueue> _queue;
private readonly WorkspaceTaskSchedulerFactory _factory;
public VisualStudioTaskScheduler(WorkspaceTaskSchedulerFactory factory)
{
_factory = factory;
_queue = new Lazy<WorkspaceTaskQueue>(CreateQueue);
}
private WorkspaceTaskQueue CreateQueue()
{
// At this point, we have to know what the UI thread is.
Contract.ThrowIfTrue(ForegroundThreadAffinitizedObject.CurrentForegroundThreadData.Kind == ForegroundThreadDataKind.Unknown);
return new WorkspaceTaskQueue(_factory, ForegroundThreadAffinitizedObject.CurrentForegroundThreadData.TaskScheduler);
}
public Task ScheduleTask(Action taskAction, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return _queue.Value.ScheduleTask(taskAction, taskName, cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<T> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return _queue.Value.ScheduleTask(taskFunc, taskName, cancellationToken);
}
public Task ScheduleTask(Func<Task> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return _queue.Value.ScheduleTask(taskFunc, taskName, cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<Task<T>> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return _queue.Value.ScheduleTask(taskFunc, taskName, cancellationToken);
}
}
}
}
......@@ -23,6 +23,7 @@
using Microsoft.VisualStudio.Shell.Interop;
using NuGet.VisualStudio;
using Roslyn.Utilities;
using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
{
......@@ -40,6 +41,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
......@@ -60,12 +62,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;
}
......@@ -78,7 +82,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<IVsPackageInstaller2>().FirstOrDefault();
......@@ -149,7 +153,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)
{
......@@ -318,7 +322,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
// they've all come in.
var cancellationToken = _tokenSource.Token;
Task.Delay(TimeSpan.FromSeconds(1), cancellationToken)
.ContinueWith(_ => ProcessBatchedChangesOnForeground(cancellationToken), cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, this.ForegroundTaskScheduler);
.ContinueWith(_ => ProcessBatchedChangesOnForeground(cancellationToken), cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, ForegroundTaskScheduler);
}
}
......@@ -500,7 +504,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;
......@@ -616,4 +620,4 @@ public void UninstallPackage(EnvDTE.Project project, string packageId, bool remo
=> _packageUninstaller.UninstallPackage(project, packageId, removeDependencies);
}
}
}
\ No newline at end of file
}
......@@ -119,6 +119,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\ProjectSystem\VisualStudioWorkspaceImpl.AbstractAddDocumentUndoUnit.cs" />
<Compile Include="Implementation\ProjectSystem\VisualStudioWorkspaceImpl.AbstractRemoveDocumentUndoUnit.cs" />
<Compile Include="Implementation\ProjectSystem\VisualStudioWorkspaceImpl.AddAdditionalDocumentUndoUnit.cs" />
......@@ -173,6 +174,7 @@
<Compile Include="Implementation\Workspace\VisualStudioNavigationOptions.cs" />
<Compile Include="Implementation\Workspace\VisualStudioNavigationOptionsProvider.cs" />
<Compile Include="Implementation\Workspace\VisualStudioProjectCacheHostServiceFactory.cs" />
<Compile Include="Implementation\Workspace\VisualStudioTaskSchedulerFactory.cs" />
<Compile Include="Packaging\Interop\SVsRemoteControlService.cs" />
<Compile Include="Packaging\IPackageServicesProxy.cs" />
<Compile Include="Storage\VisualStudioPersistentStorageLocationService.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
......@@ -521,7 +521,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;
......@@ -409,7 +409,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.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
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;
......@@ -33,19 +35,12 @@ internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
[ImportingConstructor]
private RoslynVisualStudioWorkspace(
SVsServiceProvider serviceProvider,
SaveEventsService saveEventsService,
ExportProvider exportProvider,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
[ImportMany] IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> referencedSymbolsPresenters,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories)
: base(
serviceProvider,
backgroundWork: WorkspaceBackgroundWork.ParseAndCompile)
: base(exportProvider.AsExportProvider())
{
PrimaryWorkspace.Register(this);
InitializeStandardVisualStudioWorkspace(serviceProvider, saveEventsService);
_streamingPresenters = streamingPresenters;
_referencedSymbolsPresenters = referencedSymbolsPresenters;
......@@ -62,7 +57,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));
......@@ -94,7 +95,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;
......@@ -150,7 +151,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)
......
......@@ -6,6 +6,7 @@
"Microsoft.VisualStudio.Shell.15.0": "15.0.26127-alpha",
"Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime": "14.3.25407",
"Microsoft.VisualStudio.ComponentModelHost": "15.0.26127-alpha",
"Microsoft.VisualStudio.Composition": "15.0.66-rc",
"Microsoft.VisualStudio.Diagnostics.PerformanceProvider": "15.0.26127-alpha",
"Microsoft.VisualStudio.ImageCatalog": "15.0.26127-alpha",
"Microsoft.VisualStudio.Text.UI": "15.0.26127-alpha",
......
......@@ -68,7 +68,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);
}
}
......
......@@ -71,7 +71,7 @@ private static async Task RegisterWorkspaceHostAsync(Workspace workspace, Remote
// to UI thread to run.
await Task.Factory.SafeStartNew(() =>
{
vsWorkspace.ProjectTracker.RegisterWorkspaceHost(host);
vsWorkspace.GetProjectTrackerAndInitializeIfNecessary(Shell.ServiceProvider.GlobalProvider).RegisterWorkspaceHost(host);
}, CancellationToken.None, ForegroundThreadAffinitizedObject.CurrentForegroundThreadData.TaskScheduler).ConfigureAwait(false);
}
......@@ -157,4 +157,4 @@ private static async Task<Stream> RequestServiceAsync(HubClient client, string s
return Contract.FailWithReturn<Stream>("Fail to get service. look FatalError.s_reportedException for more detail");
}
}
}
\ No newline at end of file
}
......@@ -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>());
......
......@@ -32,14 +32,12 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
/// clients. Also takes the <see cref="IGlobalOptionService.OptionChanged"/> notifications
/// and forwards them along using the same <see cref="IWorkspaceTaskScheduler"/> used by the
/// <see cref="Workspace"/> this is connected to. i.e. instead of synchronously just passing
/// along the underlying events, these will be enqueued onto the workspaces eventing queue.
/// along the underlying events, these will be enqueued onto the workspace's eventing queue.
/// </summary>
// Internal for testing purposes.
internal class OptionService : IWorkspaceOptionService
{
private readonly IGlobalOptionService _globalOptionService;
// Can be null during testing.
private readonly IWorkspaceTaskScheduler _taskQueue;
/// <summary>
......@@ -59,8 +57,8 @@ internal class OptionService : IWorkspaceOptionService
{
_globalOptionService = globalOptionService;
var workspaceTaskSchedulerFactory = workspaceServices?.GetRequiredService<IWorkspaceTaskSchedulerFactory>();
_taskQueue = workspaceTaskSchedulerFactory?.CreateTaskQueue();
var workspaceTaskSchedulerFactory = workspaceServices.GetRequiredService<IWorkspaceTaskSchedulerFactory>();
_taskQueue = workspaceTaskSchedulerFactory.CreateEventingTaskQueue();
_globalOptionService.OptionChanged += OnGlobalOptionServiceOptionChanged;
}
......@@ -74,7 +72,7 @@ public void OnWorkspaceDisposed(Workspace workspace)
private void OnGlobalOptionServiceOptionChanged(object sender, OptionChangedEventArgs e)
{
_taskQueue?.ScheduleTask(() =>
_taskQueue.ScheduleTask(() =>
{
// Ensure we grab the event handlers inside the scheduled task to prevent a race of people unsubscribing
// but getting the event later on the UI thread
......
......@@ -21,13 +21,11 @@ public static void Create(ISymbol symbol, SymbolKeyWriter visitor)
containingSymbol = containingSymbol.ContainingSymbol;
}
var compilation = ((ISourceAssemblySymbol)symbol.ContainingAssembly).Compilation;
var kind = symbol.Kind;
var localName = symbol.Name;
Contract.ThrowIfNull(
visitor.Compilation,
message: $"visitor cannot be created with a null compilation and visit a {nameof(BodyLevelSymbolKey)}.");
var ordinal = 0;
foreach (var possibleSymbol in EnumerateSymbols(visitor.Compilation, containingSymbol, kind, localName, visitor.CancellationToken))
foreach (var possibleSymbol in EnumerateSymbols(compilation, containingSymbol, kind, localName, visitor.CancellationToken))
{
if (possibleSymbol.symbol.Equals(symbol))
{
......
......@@ -60,7 +60,6 @@ private class SymbolKeyWriter : SymbolVisitor<object>, IDisposable
private readonly Dictionary<ISymbol, int> _symbolToId = new Dictionary<ISymbol, int>();
private readonly StringBuilder _stringBuilder = new StringBuilder();
public Compilation Compilation { get; private set; }
public CancellationToken CancellationToken { get; private set; }
private List<IMethodSymbol> _methodSymbolStack = new List<IMethodSymbol>();
......@@ -83,7 +82,6 @@ public void Dispose()
_symbolToId.Clear();
_stringBuilder.Clear();
_methodSymbolStack.Clear();
Compilation = null;
CancellationToken = default(CancellationToken);
_nestingCount = 0;
_nextId = 0;
......@@ -92,16 +90,15 @@ public void Dispose()
s_writerPool.Free(this);
}
public static SymbolKeyWriter GetWriter(Compilation compilation, CancellationToken cancellationToken)
public static SymbolKeyWriter GetWriter(CancellationToken cancellationToken)
{
var visitor = s_writerPool.Allocate();
visitor.Initialize(compilation, cancellationToken);
visitor.Initialize(cancellationToken);
return visitor;
}
private void Initialize(Compilation compilation, CancellationToken cancellationToken)
private void Initialize(CancellationToken cancellationToken)
{
Compilation = compilation;
CancellationToken = cancellationToken;
}
......
......@@ -116,9 +116,7 @@ public static SymbolKey Create(ISymbol symbol, CancellationToken cancellationTok
public static string ToString(ISymbol symbol, CancellationToken cancellationToken = default(CancellationToken))
{
var compilation = (symbol.ContainingAssembly as ISourceAssemblySymbol)?.Compilation;
using (var writer = SymbolKeyWriter.GetWriter(compilation, cancellationToken))
using (var writer = SymbolKeyWriter.GetWriter(cancellationToken))
{
writer.WriteFirstSymbolKey(symbol);
return writer.CreateKey();
......
......@@ -10,13 +10,14 @@ namespace Microsoft.CodeAnalysis.Host
internal interface IWorkspaceTaskSchedulerFactory : IWorkspaceService
{
/// <summary>
/// Creates a workspace task scheduler that schedules tasks to run in parallel.
/// Creates a workspace task scheduler that schedules tasks to run in parallel on the background.
/// </summary>
IWorkspaceTaskScheduler CreateTaskScheduler(TaskScheduler taskScheduler = null);
IWorkspaceTaskScheduler CreateBackgroundTaskScheduler();
/// <summary>
/// Creates a workspace task scheduler that schedules task to run in sequence.
/// Creates a workspace task scheduler that schedules task to run in sequence to be used for raising
/// workspace events.
/// </summary>
IWorkspaceTaskScheduler CreateTaskQueue(TaskScheduler taskScheduler = null);
IWorkspaceTaskScheduler CreateEventingTaskQueue();
}
}
......@@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Host
{
internal partial class WorkspaceTaskSchedulerFactory
{
internal sealed class WorkspaceTaskQueue : IWorkspaceTaskScheduler
protected sealed class WorkspaceTaskQueue : IWorkspaceTaskScheduler
{
private readonly WorkspaceTaskSchedulerFactory _factory;
private readonly SimpleTaskQueue _queue;
......
// 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.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
internal partial class WorkspaceTaskSchedulerFactory
{
private class WorkspaceTaskScheduler : IWorkspaceTaskScheduler
{
private readonly WorkspaceTaskSchedulerFactory _factory;
private readonly TaskScheduler _taskScheduler;
public WorkspaceTaskScheduler(WorkspaceTaskSchedulerFactory factory, TaskScheduler taskScheduler)
{
_factory = factory;
_taskScheduler = taskScheduler;
}
private TTask ScheduleTaskWorker<TTask>(
string taskName, Func<TTask> taskCreator, CancellationToken cancellationToken)
where TTask : Task
{
taskName = taskName ?? GetType().Name + ".ScheduleTask";
var asyncToken = _factory.BeginAsyncOperation(taskName);
var task = taskCreator();
_factory.CompleteAsyncOperation(asyncToken, task);
return task;
}
public Task ScheduleTask(Action taskAction, string taskName, CancellationToken cancellationToken)
{
return ScheduleTaskWorker(
taskName, () => Task.Factory.SafeStartNew(taskAction, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<T> taskFunc, string taskName, CancellationToken cancellationToken)
{
return ScheduleTaskWorker(
taskName, () => Task.Factory.SafeStartNew(taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task ScheduleTask(Func<Task> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return ScheduleTaskWorker(
taskName, () => Task.Factory.SafeStartNewFromAsync(taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<Task<T>> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return ScheduleTaskWorker(
taskName, () => Task.Factory.SafeStartNewFromAsync(taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
}
}
}
// 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 Microsoft.CodeAnalysis.Host.Mef;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
[ExportWorkspaceService(typeof(IWorkspaceTaskSchedulerFactory), ServiceLayer.Default)]
[Shared]
internal partial class WorkspaceTaskSchedulerFactory : IWorkspaceTaskSchedulerFactory
{
public virtual IWorkspaceTaskScheduler CreateTaskScheduler(TaskScheduler taskScheduler = null)
public virtual IWorkspaceTaskScheduler CreateBackgroundTaskScheduler()
{
if (taskScheduler == null)
{
taskScheduler = (SynchronizationContext.Current != null)
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Default;
}
return new WorkspaceTaskScheduler(this, taskScheduler);
return new WorkspaceTaskScheduler(this, TaskScheduler.Default);
}
public virtual IWorkspaceTaskScheduler CreateTaskQueue(TaskScheduler taskScheduler = null)
public virtual IWorkspaceTaskScheduler CreateEventingTaskQueue()
{
if (taskScheduler == null)
{
taskScheduler = (SynchronizationContext.Current != null)
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Default;
}
var taskScheduler = (SynchronizationContext.Current != null)
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Default;
return new WorkspaceTaskQueue(this, taskScheduler);
}
......@@ -43,62 +35,5 @@ protected virtual void CompleteAsyncOperation(object asyncToken, Task task)
{
// do nothing ... overridden by services layer
}
private class WorkspaceTaskScheduler : IWorkspaceTaskScheduler
{
private readonly WorkspaceTaskSchedulerFactory _factory;
private readonly TaskScheduler _taskScheduler;
public WorkspaceTaskScheduler(WorkspaceTaskSchedulerFactory factory, TaskScheduler taskScheduler)
{
_factory = factory;
_taskScheduler = taskScheduler;
}
private TTask ScheduleTaskWorker<TTask>(
string taskName, Func<TTask> taskCreator, CancellationToken cancellationToken)
where TTask : Task
{
taskName = taskName ?? GetType().Name + ".ScheduleTask";
var asyncToken = _factory.BeginAsyncOperation(taskName);
var task = taskCreator();
_factory.CompleteAsyncOperation(asyncToken, task);
return task;
}
public Task ScheduleTask(Action taskAction, string taskName, CancellationToken cancellationToken)
{
return ScheduleTaskWorker<Task>(
taskName, () => Task.Factory.SafeStartNew(
taskAction, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<T> taskFunc, string taskName, CancellationToken cancellationToken)
{
return ScheduleTaskWorker<Task<T>>(
taskName, () => Task.Factory.SafeStartNew(
taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task ScheduleTask(Func<Task> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return ScheduleTaskWorker<Task>(
taskName, () => Task.Factory.SafeStartNewFromAsync(
taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
public Task<T> ScheduleTask<T>(Func<Task<T>> taskFunc, string taskName, CancellationToken cancellationToken = default(CancellationToken))
{
return ScheduleTaskWorker<Task<T>>(
taskName, () => Task.Factory.SafeStartNewFromAsync(
taskFunc, cancellationToken, _taskScheduler),
cancellationToken);
}
}
}
}
// 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.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Host
{
[ExportWorkspaceServiceFactory(typeof(IWorkspaceTaskSchedulerFactory), ServiceLayer.Default)]
[Shared]
internal class WorkspaceTaskSchedulerFactoryFactory : IWorkspaceServiceFactory
{
private readonly WorkspaceTaskSchedulerFactory _singleton = new WorkspaceTaskSchedulerFactory();
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return _singleton;
}
}
}
......@@ -11,12 +11,8 @@ namespace Microsoft.CodeAnalysis
internal static class PrimaryWorkspace
{
private static readonly ReaderWriterLockSlim s_registryGate = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private static Workspace s_primaryWorkspace;
private static readonly List<TaskCompletionSource<Workspace>> s_primaryWorkspaceTaskSourceList =
new List<TaskCompletionSource<Workspace>>();
/// <summary>
/// The primary workspace, usually set by the host environment.
/// </summary>
......@@ -44,56 +40,6 @@ public static void Register(Workspace workspace)
using (s_registryGate.DisposableWrite())
{
s_primaryWorkspace = workspace;
foreach (var taskSource in s_primaryWorkspaceTaskSourceList)
{
try
{
taskSource.TrySetResult(workspace);
}
catch
{
}
}
s_primaryWorkspaceTaskSourceList.Clear();
}
}
/// <summary>
/// Get's the primary workspace asynchronously.
/// </summary>
public static Task<Workspace> GetWorkspaceAsync(CancellationToken cancellationToken = default(CancellationToken))
{
using (s_registryGate.DisposableWrite())
{
if (s_primaryWorkspace != null)
{
return Task<Workspace>.FromResult(s_primaryWorkspace);
}
else
{
var taskSource = new TaskCompletionSource<Workspace>();
if (cancellationToken.CanBeCanceled)
{
try
{
var registration = cancellationToken.Register(() =>
{
taskSource.TrySetCanceled();
});
taskSource.Task.ContinueWith(_ => registration.Dispose(), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
catch
{
}
}
s_primaryWorkspaceTaskSourceList.Add(taskSource);
return taskSource.Task;
}
}
}
}
......
......@@ -63,7 +63,7 @@ protected Workspace(HostServices host, string workspaceKind)
// queue used for sending events
var workspaceTaskSchedulerFactory = _services.GetRequiredService<IWorkspaceTaskSchedulerFactory>();
_taskQueue = workspaceTaskSchedulerFactory.CreateTaskQueue();
_taskQueue = workspaceTaskSchedulerFactory.CreateEventingTaskQueue();
// initialize with empty solution
_latestSolution = CreateSolution(SolutionId.CreateNewId());
......
......@@ -411,6 +411,7 @@
<Compile Include="NamingStyles\Serialization\SymbolSpecification.cs" />
<Compile Include="Shared\Extensions\SolutionExtensions.cs" />
<Compile Include="SymbolKey\SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs" />
<Compile Include="Workspace\Host\TaskScheduler\WorkspaceTaskSchedulerFactory.WorkspaceTaskScheduler.cs" />
<Compile Include="Tags\WellKnownTags.cs" />
<Compile Include="Workspace\Solution\Checksum.cs" />
<Compile Include="Execution\RemotableData.cs" />
......@@ -1009,7 +1010,6 @@
<Compile Include="Workspace\Host\TaskScheduler\IWorkspaceTaskSchedulerFactory.cs" />
<Compile Include="Workspace\Host\TaskScheduler\WorkspaceTaskSchedulerFactory.cs" />
<Compile Include="Workspace\Host\TaskScheduler\WorkspaceTaskSchedulerFactory.WorkspaceTaskQueue.cs" />
<Compile Include="Workspace\Host\TaskScheduler\WorkspaceTaskSchedulerFactoryFactory.cs" />
<Compile Include="Workspace\Host\TemporaryStorage\ISupportDirectMemoryAccess.cs" />
<Compile Include="Workspace\Host\TemporaryStorage\ITemporaryStorage.cs" />
<Compile Include="Workspace\Host\TemporaryStorage\ITemporaryStorageWithName.cs" />
......@@ -1130,4 +1130,4 @@
</ItemGroup>
<Import Project="..\..\..\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems" Label="Shared" />
<Import Project="..\..\..\..\build\Targets\Imports.targets" />
</Project>
\ No newline at end of file
</Project>
......@@ -6,6 +6,7 @@
using System.Linq;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.UnitTests
{
......@@ -19,7 +20,7 @@ public static OptionServiceFactory.OptionService GetService()
{
new Lazy<IOptionProvider>(() => new TestOptionsProvider())
},
Enumerable.Empty<Lazy<IOptionPersister>>()), workspaceServices: null);
Enumerable.Empty<Lazy<IOptionPersister>>()), workspaceServices: new AdhocWorkspace().Services);
}
internal class TestOptionsProvider : IOptionProvider
......
......@@ -579,6 +579,47 @@ void foo()
Assert.NotNull(SymbolKey.Create(xSymbol));
}
[Fact, WorkItem(377839, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=377839")]
public void TestConstructedMethodInsideLocalFunctionWithTypeParameters()
{
var source = @"
using System.Linq;
class C
{
void Method()
{
object LocalFunction<T>()
{
return Enumerable.Empty<T>();
}
}
}";
var compilation = GetCompilation(source, LanguageNames.CSharp);
var symbols = GetAllSymbols(
compilation.GetSemanticModel(compilation.SyntaxTrees.Single()),
n => n is CSharp.Syntax.MemberAccessExpressionSyntax || n is CSharp.Syntax.InvocationExpressionSyntax);
var tested = false;
foreach (var symbol in symbols)
{
// Ensure we don't crash getting these symbol keys.
var id = SymbolKey.ToString(symbol);
Assert.NotNull(id);
var found = SymbolKey.Resolve(id, compilation).GetAnySymbol();
Assert.NotNull(found);
// note: we don't check that the symbols are equal. That's because the compiler
// doesn't guarantee that the TypeParameters will be hte same across successive
// invocations.
Assert.Equal(symbol.OriginalDefinition, found.OriginalDefinition);
tested = true;
}
Assert.True(tested);
}
private void TestRoundTrip(IEnumerable<ISymbol> symbols, Compilation compilation, Func<ISymbol, object> fnId = null)
{
foreach (var symbol in symbols)
......@@ -608,46 +649,58 @@ private void TestRoundTrip(ISymbol symbol, Compilation compilation, Func<ISymbol
private Compilation GetCompilation(string source, string language)
{
var references = new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
if (language == LanguageNames.CSharp)
{
var tree = CSharp.SyntaxFactory.ParseSyntaxTree(source);
return CSharp.CSharpCompilation.Create("Test", syntaxTrees: new[] { tree }, references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
return CSharp.CSharpCompilation.Create("Test", syntaxTrees: new[] { tree }, references: references);
}
else if (language == LanguageNames.VisualBasic)
{
var tree = VisualBasic.SyntaxFactory.ParseSyntaxTree(source);
return VisualBasic.VisualBasicCompilation.Create("Test", syntaxTrees: new[] { tree }, references: new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
return VisualBasic.VisualBasicCompilation.Create("Test", syntaxTrees: new[] { tree }, references: references);
}
throw new NotSupportedException();
}
private List<ISymbol> GetAllSymbols(SemanticModel model)
private List<ISymbol> GetAllSymbols(
SemanticModel model, Func<SyntaxNode, bool> predicate = null)
{
var list = new List<ISymbol>();
GetAllSymbols(model, model.SyntaxTree.GetRoot(), list);
GetAllSymbols(model, model.SyntaxTree.GetRoot(), list, predicate);
return list;
}
private void GetAllSymbols(SemanticModel model, SyntaxNode node, List<ISymbol> list)
private void GetAllSymbols(
SemanticModel model, SyntaxNode node,
List<ISymbol> list, Func<SyntaxNode, bool> predicate)
{
var symbol = model.GetDeclaredSymbol(node);
if (symbol != null)
if (predicate == null || predicate(node))
{
list.Add(symbol);
}
var symbol = model.GetDeclaredSymbol(node);
if (symbol != null)
{
list.Add(symbol);
}
symbol = model.GetSymbolInfo(node).GetAnySymbol();
if (symbol != null)
{
list.Add(symbol);
symbol = model.GetSymbolInfo(node).GetAnySymbol();
if (symbol != null)
{
list.Add(symbol);
}
}
foreach (var child in node.ChildNodesAndTokens())
{
if (child.IsNode)
{
GetAllSymbols(model, child.AsNode(), list);
GetAllSymbols(model, child.AsNode(), list, predicate);
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册