diff --git a/NuGet.Config b/NuGet.Config
index 829348448412cd47c87d0335e603b6887e82ccae..86001b761c0d4c475eeba9a0da12fcbe88cf1a41 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -24,6 +24,7 @@
+
diff --git a/Roslyn.sln b/Roslyn.sln
index d7608d3a828b7c7f04963d492686356f1733a57e..5040f8acb15b8d134b28fec5f6fc8008c4bac80a 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -374,6 +374,12 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Meta
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.PooledObjects", "src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.shproj", "{C1930979-C824-496B-A630-70F5369A636F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicesVisualStudio.Next", "src\VisualStudio\Next\ServicesVisualStudio.Next.csproj", "{FE0D4BDD-1C30-488E-A870-854F5B8C5014}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteWorkspaces", "src\Workspaces\Remote\Core\RemoteWorkspaces.csproj", "{F822F72A-CC87-4E31-B57D-853F65CBEBF3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceHub", "src\Workspaces\Remote\ServiceHub\ServiceHub.csproj", "{80FDDD00-9393-47F7-8BAF-7E87CE011068}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Compilers\Core\CommandLine\CommandLine.projitems*{06b26dcb-7a12-48ef-ae50-708593abd05f}*SharedItemsImports = 4
@@ -3205,6 +3211,66 @@ Global
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x64.Build.0 = Release|Any CPU
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x86.ActiveCfg = Release|Any CPU
{3DA711E1-055F-4352-A5E1-F9169C86A20F}.Release|x86.Build.0 = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|ARM.Build.0 = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x64.Build.0 = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Debug|x86.Build.0 = Debug|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|ARM.ActiveCfg = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|ARM.Build.0 = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x64.ActiveCfg = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x64.Build.0 = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x86.ActiveCfg = Release|Any CPU
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014}.Release|x86.Build.0 = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|ARM.Build.0 = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x64.Build.0 = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Debug|x86.Build.0 = Debug|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|ARM.ActiveCfg = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|ARM.Build.0 = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x64.ActiveCfg = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x64.Build.0 = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x86.ActiveCfg = Release|Any CPU
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3}.Release|x86.Build.0 = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|ARM.Build.0 = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x64.Build.0 = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Debug|x86.Build.0 = Debug|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Any CPU.Build.0 = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|ARM.ActiveCfg = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|ARM.Build.0 = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x64.ActiveCfg = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x64.Build.0 = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x86.ActiveCfg = Release|Any CPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3376,5 +3442,8 @@ Global
{3DA711E1-055F-4352-A5E1-F9169C86A20F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{D73ADF7D-2C1C-42AE-B2AB-EDC9497E4B71} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{C1930979-C824-496B-A630-70F5369A636F} = {C2D1346B-9665-4150-B644-075CF1636BAA}
+ {FE0D4BDD-1C30-488E-A870-854F5B8C5014} = {8DBA5174-B0AA-4561-82B1-A46607697753}
+ {F822F72A-CC87-4E31-B57D-853F65CBEBF3} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
EndGlobalSection
EndGlobal
diff --git a/src/Tools/SignRoslyn/BatchSignData.json b/src/Tools/SignRoslyn/BatchSignData.json
index 74111b43081f4e8bccfcfa7c3dd8e9b1a6de86dc..0222bdbe68056cd21430de199dea8fe96bc94f28 100644
--- a/src/Tools/SignRoslyn/BatchSignData.json
+++ b/src/Tools/SignRoslyn/BatchSignData.json
@@ -3,62 +3,65 @@
{
"certificate": "Microsoft402",
"strongName": "MsSharedLib72",
- "values": [
- "csc.exe",
- "csccore\\csc.exe",
- "csi.exe",
- "csicore\\csi.exe",
- "InteractiveHost.exe",
- "Microsoft.Build.Tasks.CodeAnalysis.dll",
- "Microsoft.CodeAnalysis.CSharp.dll",
- "Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll",
- "Microsoft.CodeAnalysis.CSharp.Features.dll",
- "Microsoft.CodeAnalysis.CSharp.InteractiveEditorFeatures.dll",
- "Microsoft.CodeAnalysis.CSharp.Scripting.dll",
- "Microsoft.CodeAnalysis.CSharp.Workspaces.dll",
- "Microsoft.CodeAnalysis.dll",
- "Microsoft.CodeAnalysis.EditorFeatures.dll",
- "Microsoft.CodeAnalysis.EditorFeatures.Next.dll",
- "Microsoft.CodeAnalysis.EditorFeatures.Text.dll",
- "Microsoft.CodeAnalysis.Features.dll",
- "Microsoft.CodeAnalysis.InteractiveEditorFeatures.dll",
- "Microsoft.CodeAnalysis.InteractiveFeatures.dll",
- "Microsoft.CodeAnalysis.Scripting.dll",
- "Microsoft.CodeAnalysis.VisualBasic.dll",
- "Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.dll",
- "Microsoft.CodeAnalysis.VisualBasic.Features.dll",
- "Microsoft.CodeAnalysis.VisualBasic.InteractiveEditorFeatures.dll",
- "Microsoft.CodeAnalysis.VisualBasic.Scripting.dll",
- "Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll",
- "Microsoft.CodeAnalysis.Workspaces.Desktop.dll",
- "Microsoft.CodeAnalysis.Workspaces.dll",
- "Microsoft.DiaSymReader.PortablePdb.dll",
- "Microsoft.VisualStudio.CSharp.Repl.dll",
- "Microsoft.VisualStudio.InteractiveServices.dll",
- "Microsoft.VisualStudio.InteractiveWindow.dll",
- "Microsoft.VisualStudio.LanguageServices.CSharp.dll",
- "Microsoft.VisualStudio.LanguageServices.dll",
- "Microsoft.VisualStudio.LanguageServices.Implementation.dll",
- "Microsoft.VisualStudio.LanguageServices.SolutionExplorer.dll",
- "Microsoft.VisualStudio.LanguageServices.VisualBasic.dll",
- "Microsoft.VisualStudio.VisualBasic.Repl.dll",
- "Microsoft.VisualStudio.VsInteractiveWindow.dll",
- "Pdb2Xml.exe",
- "Roslyn.Compilers.Extension.dll",
- "Roslyn.Hosting.Diagnostics.dll",
- "Roslyn.VisualStudio.DiagnosticsWindow.dll",
- "Roslyn.VisualStudio.InteractiveComponents.dll",
- "Roslyn.VisualStudio.Setup.Interactive.dll",
- "SDK\\Roslyn.SyntaxVisualizer.DgmlHelper.dll",
- "SDK\\Roslyn.SyntaxVisualizer.Control.dll",
- "SDK\\Roslyn.SyntaxVisualizer.Extension.dll",
- "SDK\\Roslyn.Templates.dll",
- "vbc.exe",
- "vbccore\\vbc.exe",
- "VBCSCompiler.exe",
- "vbi.exe",
- "vbicore\\vbi.exe"
- ]
+ "values": [
+ "csc.exe",
+ "csccore\\csc.exe",
+ "csi.exe",
+ "csicore\\csi.exe",
+ "InteractiveHost.exe",
+ "Microsoft.Build.Tasks.CodeAnalysis.dll",
+ "Microsoft.CodeAnalysis.CSharp.dll",
+ "Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll",
+ "Microsoft.CodeAnalysis.CSharp.Features.dll",
+ "Microsoft.CodeAnalysis.CSharp.InteractiveEditorFeatures.dll",
+ "Microsoft.CodeAnalysis.CSharp.Scripting.dll",
+ "Microsoft.CodeAnalysis.CSharp.Workspaces.dll",
+ "Microsoft.CodeAnalysis.dll",
+ "Microsoft.CodeAnalysis.EditorFeatures.dll",
+ "Microsoft.CodeAnalysis.EditorFeatures.Next.dll",
+ "Microsoft.CodeAnalysis.EditorFeatures.Text.dll",
+ "Microsoft.CodeAnalysis.Features.dll",
+ "Microsoft.CodeAnalysis.InteractiveEditorFeatures.dll",
+ "Microsoft.CodeAnalysis.InteractiveFeatures.dll",
+ "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
+ "Microsoft.CodeAnalysis.Remote.Workspaces.dll",
+ "Microsoft.CodeAnalysis.Scripting.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.Features.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.InteractiveEditorFeatures.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.Scripting.dll",
+ "Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll",
+ "Microsoft.CodeAnalysis.Workspaces.Desktop.dll",
+ "Microsoft.CodeAnalysis.Workspaces.dll",
+ "Microsoft.DiaSymReader.PortablePdb.dll",
+ "Microsoft.VisualStudio.CSharp.Repl.dll",
+ "Microsoft.VisualStudio.InteractiveServices.dll",
+ "Microsoft.VisualStudio.InteractiveWindow.dll",
+ "Microsoft.VisualStudio.LanguageServices.CSharp.dll",
+ "Microsoft.VisualStudio.LanguageServices.dll",
+ "Microsoft.VisualStudio.LanguageServices.Implementation.dll",
+ "Microsoft.VisualStudio.LanguageServices.Next.dll",
+ "Microsoft.VisualStudio.LanguageServices.SolutionExplorer.dll",
+ "Microsoft.VisualStudio.LanguageServices.VisualBasic.dll",
+ "Microsoft.VisualStudio.VisualBasic.Repl.dll",
+ "Microsoft.VisualStudio.VsInteractiveWindow.dll",
+ "Pdb2Xml.exe",
+ "Roslyn.Compilers.Extension.dll",
+ "Roslyn.Hosting.Diagnostics.dll",
+ "Roslyn.VisualStudio.DiagnosticsWindow.dll",
+ "Roslyn.VisualStudio.InteractiveComponents.dll",
+ "Roslyn.VisualStudio.Setup.Interactive.dll",
+ "SDK\\Roslyn.SyntaxVisualizer.DgmlHelper.dll",
+ "SDK\\Roslyn.SyntaxVisualizer.Control.dll",
+ "SDK\\Roslyn.SyntaxVisualizer.Extension.dll",
+ "SDK\\Roslyn.Templates.dll",
+ "vbc.exe",
+ "vbccore\\vbc.exe",
+ "VBCSCompiler.exe",
+ "vbi.exe",
+ "vbicore\\vbi.exe"
+ ]
},
{
"certificate": "WindowsPhone623",
@@ -108,6 +111,9 @@
"Microsoft.DiaSymReader.dll",
"Microsoft.DiaSymReader.Native.amd64.dll",
"Microsoft.DiaSymReader.Native.x86.dll",
+ "Newtonsoft.Json.dll",
+ "StreamJsonRpc.dll",
+ "StreamJsonRpc.resources.dll",
"System.Reflection.Metadata.dll",
"System.Collections.Immutable.dll",
"System.Diagnostics.StackTrace.dll",
diff --git a/src/VisualStudio/Next/Diagnostics/OutOfProcCompilerDiagnosticAnalyzer.cs b/src/VisualStudio/Next/Diagnostics/OutOfProcCompilerDiagnosticAnalyzer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d086dc5e073e5ba555892079b66642d6a9d118f1
--- /dev/null
+++ b/src/VisualStudio/Next/Diagnostics/OutOfProcCompilerDiagnosticAnalyzer.cs
@@ -0,0 +1,171 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
+using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
+using Microsoft.CodeAnalysis.Execution;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Remote.Diagnostics;
+using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
+using Microsoft.VisualStudio.LanguageServices.Implementation.Remote;
+using Roslyn.Utilities;
+
+namespace Microsoft.VisualStudio.LanguageServices.Diagnostics
+{
+ [ExportWorkspaceService(typeof(ICompilerDiagnosticAnalyzer), layer: ServiceLayer.Host), Shared]
+ internal class OutOfProcCompilerDiagnosticAnalyzer : ICompilerDiagnosticAnalyzer
+ {
+ private static readonly ICompilerDiagnosticAnalyzer _inProcAnalyzer = new InProcCompilerDiagnosticAnalyzer();
+
+ private readonly IDiagnosticAnalyzerService _analyzerService;
+ private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSource;
+
+ // TODO: solution snapshot tracking for current solution should be its own service
+ private ChecksumScope _lastSnapshot;
+
+ [ImportingConstructor]
+ public OutOfProcCompilerDiagnosticAnalyzer(
+ IDiagnosticAnalyzerService analyzerService,
+ AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
+ {
+ _analyzerService = analyzerService;
+ _hostDiagnosticUpdateSource = hostDiagnosticUpdateSource;
+ }
+
+ public async Task> AnalyzeAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
+ {
+ var remoteHostClient = await project.Solution.Workspace.Services.GetService().GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
+ if (remoteHostClient == null)
+ {
+ // remote host is not running. this can happen if remote host is disabled.
+ return await AnalyzeInProcAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
+ }
+
+ // TODO: later, make sure we can run all analyzer on remote host.
+ // for now, we will check whether built in analyzer can run on remote host and only those run on remote host.
+ var inProcResultTask = AnalyzeInProcAsync(CreateAnalyzerDriver(analyzerDriver, a => a.MustRunInProc()), project, cancellationToken);
+ var outOfProcResultTask = AnalyzeOutOfProcAsync(remoteHostClient, analyzerDriver, project, cancellationToken);
+
+ // run them concurrently in vs and remote host
+ await Task.WhenAll(inProcResultTask, outOfProcResultTask).ConfigureAwait(false);
+
+ // make sure things are not cancelled
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // merge 2 results
+ return DiagnosticAnalysisResultMap.Create(
+ inProcResultTask.Result.AnalysisResult.AddRange(outOfProcResultTask.Result.AnalysisResult),
+ inProcResultTask.Result.TelemetryInfo.AddRange(outOfProcResultTask.Result.TelemetryInfo));
+ }
+
+ private async Task> AnalyzeInProcAsync(CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
+ {
+ return await _inProcAnalyzer.AnalyzeAsync(analyzerDriver, project, cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task> AnalyzeOutOfProcAsync(
+ RemoteHostClient client, CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken)
+ {
+ var solution = project.Solution;
+
+ var snapshotService = solution.Workspace.Services.GetService();
+
+ // TODO: incremental build of solution snapshot should be its own service
+ await UpdateLastSolutionSnapshotAsync(snapshotService, solution).ConfigureAwait(false);
+
+ // TODO: this should be moved out
+ var hostChecksums = GetHostAnalyzerReferences(snapshotService, _analyzerService.GetHostAnalyzerReferences(), cancellationToken);
+ var analyzerMap = CreateAnalyzerMap(analyzerDriver.Analyzers.Where(a => !a.MustRunInProc()));
+ if (analyzerMap.Count == 0)
+ {
+ return DiagnosticAnalysisResultMap.Create(ImmutableDictionary.Empty, ImmutableDictionary.Empty);
+ }
+
+ // TODO: send telemetry on session
+ using (var session = await client.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
+ {
+ var argument = new DiagnosticArguments(
+ analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
+ analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
+ project.Id, hostChecksums, analyzerMap.Keys.ToArray());
+
+ var result = await session.InvokeAsync(
+ WellKnownServiceHubServices.CodeAnalysisService_CalculateDiagnosticsAsync,
+ new object[] { argument },
+ (s, c) => GetCompilerAnalysisResultAsync(s, analyzerMap, project, c)).ConfigureAwait(false);
+
+ ReportAnalyzerExceptions(project, result.Exceptions);
+
+ return result;
+ }
+ }
+
+ private async Task UpdateLastSolutionSnapshotAsync(ISolutionChecksumService snapshotService, Solution solution)
+ {
+ // TODO: actual incremental build of solution snapshot should be its own service
+ // this is needed to make sure we incrementally update solution checksums. otherwise, we will always create from
+ // scratch which can be quite expansive for big solution
+ var lastSnapshot = _lastSnapshot;
+ _lastSnapshot = await snapshotService.CreateChecksumAsync(solution, CancellationToken.None).ConfigureAwait(false);
+ lastSnapshot?.Dispose();
+ }
+
+ private CompilationWithAnalyzers CreateAnalyzerDriver(CompilationWithAnalyzers analyzerDriver, Func predicate)
+ {
+ var analyzers = analyzerDriver.Analyzers.Where(predicate).ToImmutableArray();
+ return analyzerDriver.Compilation.WithAnalyzers(analyzers, analyzerDriver.AnalysisOptions);
+ }
+
+ private async Task> GetCompilerAnalysisResultAsync(Stream stream, Dictionary analyzerMap, Project project, CancellationToken cancellationToken)
+ {
+ // handling of cancellation and exception
+ var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
+
+ using (var reader = new ObjectReader(stream))
+ {
+ return DiagnosticResultSerializer.Deserialize(reader, analyzerMap, project, version, cancellationToken);
+ }
+ }
+
+ private void ReportAnalyzerExceptions(Project project, ImmutableDictionary> exceptions)
+ {
+ foreach (var kv in exceptions)
+ {
+ var analyzer = kv.Key;
+ foreach (var diagnostic in kv.Value)
+ {
+ _hostDiagnosticUpdateSource.ReportAnalyzerDiagnostic(analyzer, diagnostic, project);
+ }
+ }
+ }
+
+ private ImmutableArray GetHostAnalyzerReferences(ISolutionChecksumService snapshotService, IEnumerable references, CancellationToken cancellationToken)
+ {
+ // TODO: cache this to somewhere
+ var builder = ImmutableArray.CreateBuilder();
+ foreach (var reference in references)
+ {
+ var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
+ builder.Add(asset.Checksum.ToArray());
+ }
+
+ return builder.ToImmutable();
+ }
+
+ private Dictionary CreateAnalyzerMap(IEnumerable analyzers)
+ {
+ // TODO: this needs to be cached. we can have 300+ analyzers
+ return analyzers.ToDictionary(a => a.GetAnalyzerIdAndVersion().Item1, a => a);
+ }
+ }
+}
diff --git a/src/VisualStudio/Setup.Next/AssemblyRedirects.cs b/src/VisualStudio/Setup.Next/AssemblyRedirects.cs
index f25c23bffe5c63b547694c710be9ab4915b1e518..8bd91ccc7f02a80ee9944072d96388623db5dad9 100644
--- a/src/VisualStudio/Setup.Next/AssemblyRedirects.cs
+++ b/src/VisualStudio/Setup.Next/AssemblyRedirects.cs
@@ -11,4 +11,8 @@
PublicKeyToken = "31BF3856AD364E35",
OldVersionLowerBound = "14.0.0.0",
OldVersionUpperBound = "14.9.9.9",
- NewVersion = "15.0.0.0")]
\ No newline at end of file
+ NewVersion = "15.0.0.0")]
+
+[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\StreamJsonRpc.dll")]
+[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.ServiceHub.Client.dll")]
+[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Newtonsoft.Json.dll")]
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj b/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj
index 3728183830ed66fc0ca23cba039aa0187771fcc5..6bd0ea47aa61508837e82cfbf10fdca8321505b0 100644
--- a/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj
+++ b/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj
@@ -24,6 +24,24 @@
false
+
+ {1ee8cad3-55f9-4d91-96b2-084641da9a6c}
+ CodeAnalysis
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {b501a547-c911-4a05-ac6e-274a50dff30e}
+ CSharpCodeAnalysis
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {2523d0e6-df32-4a3e-8ae0-a19bffae2ef6}
+ BasicCodeAnalysis
+ BuiltProjectOutputGroup%3b
+ true
+
{8da861d8-0cce-4334-b6c0-01a846c881ec}
VisualStudio
@@ -35,12 +53,62 @@
BuiltProjectOutputGroup%3b
DebugSymbolsProjectOutputGroup%3b
+
+ {2e87fa96-50bb-4607-8676-46521599f998}
+ Workspaces.Desktop
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {5f8d2414-064a-4b3a-9b42-8e2a04246be5}
+ Workspaces
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {21b239d0-d144-430f-a394-c066d58ee267}
+ CSharpWorkspace
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {f822f72a-cc87-4e31-b57d-853f65cbebf3}
+ RemoteWorkspaces
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {80fddd00-9393-47f7-8baf-7e87ce011068}
+ ServiceHub
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}
+ BasicWorkspace
+ BuiltProjectOutputGroup%3b
+ true
+
+
+ {fe0d4bdd-1c30-488e-a870-854f5b8c5014}
+ ServicesVisualStudio.Next
+ BuiltProjectOutputGroup%3b
+ true
+
VisualStudioSetup
false
False
+
+
+
+
+
+
+
+
AnyCPU
@@ -53,7 +121,19 @@
/rootsuffix RoslynDev /log
+
+ PreserveNewest
+ true
+
+
+ PreserveNewest
+ true
+
+
+ PreserveNewest
+ true
+
Designer
@@ -67,4 +147,4 @@
-
+
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/codeAnalysisService.servicehub.service.json b/src/VisualStudio/Setup.Next/codeAnalysisService.servicehub.service.json
new file mode 100644
index 0000000000000000000000000000000000000000..27d5cef6a817a2a69dd98e89b41d1eb11f7f50d7
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/codeAnalysisService.servicehub.service.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "../../../schemas/servicehub.service.schema.json",
+ "host": "desktopClr.x86",
+ "hostId": "RoslynCodeAnalysisService32",
+ "entryPoint": {
+ "assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
+ "fullClassName": "Microsoft.CodeAnalysis.Remote.CodeAnalysisService"
+ }
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/project.json b/src/VisualStudio/Setup.Next/project.json
index 0b16291820b6777d8fb7568842dfdb0f7ad5ebcc..edb027acd430dac19fcba13777d4b51ec70067e4 100644
--- a/src/VisualStudio/Setup.Next/project.json
+++ b/src/VisualStudio/Setup.Next/project.json
@@ -1,5 +1,7 @@
{
"dependencies": {
+ "StreamJsonRpc": "0.14.3-alpha",
+ "Newtonsoft.Json": "6.0.6"
},
"frameworks": {
"net46": { }
diff --git a/src/VisualStudio/Setup.Next/remoteHostService.servicehub.service.json b/src/VisualStudio/Setup.Next/remoteHostService.servicehub.service.json
new file mode 100644
index 0000000000000000000000000000000000000000..2aee3fe44f7e86fb715cacdd5e5913fee486a33b
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/remoteHostService.servicehub.service.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "../../../schemas/servicehub.service.schema.json",
+ "host": "desktopClr.x86",
+ "hostId": "RoslynCodeAnalysisService32",
+ "entryPoint": {
+ "assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
+ "fullClassName": "Microsoft.CodeAnalysis.Remote.RemoteHostService"
+ }
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/serviceHubSnapshotService.servicehub.service.json b/src/VisualStudio/Setup.Next/serviceHubSnapshotService.servicehub.service.json
new file mode 100644
index 0000000000000000000000000000000000000000..401220eb2506e4f18196e1fbb5ba794a22ed5f06
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/serviceHubSnapshotService.servicehub.service.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "../../../schemas/servicehub.service.schema.json",
+ "host": "desktopClr.x86",
+ "hostId": "RoslynCodeAnalysisService32",
+ "entryPoint": {
+ "assemblyPath": "Microsoft.CodeAnalysis.Remote.ServiceHub.dll",
+ "fullClassName": "Microsoft.CodeAnalysis.Remote.ServiceHubSnapshotService"
+ }
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/source.extension.vsixmanifest b/src/VisualStudio/Setup.Next/source.extension.vsixmanifest
index 02a77efbd27d3d81cc59997b3f0c12e88422f976..5c375b4515ba60c5178bd7be1b4bc4cc37ecade2 100644
--- a/src/VisualStudio/Setup.Next/source.extension.vsixmanifest
+++ b/src/VisualStudio/Setup.Next/source.extension.vsixmanifest
@@ -17,5 +17,9 @@
+
+
+
+
diff --git a/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticArguments.cs b/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticArguments.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e3c805b507835ca73664cccb2b3801891741b763
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticArguments.cs
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis.Execution;
+
+namespace Microsoft.CodeAnalysis.Remote.Diagnostics
+{
+ ///
+ /// helper type to package diagnostic arguments to pass around between remote hosts
+ ///
+ internal class DiagnosticArguments
+ {
+ public bool ReportSuppressedDiagnostics;
+ public bool LogAnalyzerExecutionTime;
+ public Guid ProjectIdGuid;
+ public string ProjectIdDebugName;
+ public byte[][] HostAnalyzerChecksumsByteArray;
+ public string[] AnalyzerIds;
+
+ public DiagnosticArguments()
+ {
+ }
+
+ public DiagnosticArguments(
+ bool reportSuppressedDiagnostics,
+ bool logAnalyzerExecutionTime,
+ ProjectId projectId,
+ ImmutableArray hostAnalyzerChecksums,
+ string[] analyzerIds)
+ {
+ ReportSuppressedDiagnostics = reportSuppressedDiagnostics;
+ LogAnalyzerExecutionTime = logAnalyzerExecutionTime;
+
+ ProjectIdGuid = projectId.Id;
+ ProjectIdDebugName = projectId.DebugName;
+
+ HostAnalyzerChecksumsByteArray = hostAnalyzerChecksums.ToArray();
+ AnalyzerIds = analyzerIds;
+ }
+
+ public ProjectId GetProjectId() => ProjectId.CreateFromSerialized(ProjectIdGuid, ProjectIdDebugName);
+ public IEnumerable GetHostAnalyzerChecksums() => HostAnalyzerChecksumsByteArray.Select(b => new Checksum(b));
+ }
+}
\ No newline at end of file
diff --git a/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticResultSerializer.cs b/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticResultSerializer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3c613ece8477cfe26507f54ce085884d70b6dea9
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Diagnostics/DiagnosticResultSerializer.cs
@@ -0,0 +1,197 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
+using Microsoft.CodeAnalysis.Execution;
+using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Remote.Diagnostics
+{
+ internal static class DiagnosticResultSerializer
+ {
+ public static void Serialize(ObjectWriter writer, DiagnosticAnalysisResultMap result, CancellationToken cancellationToken)
+ {
+ var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
+
+ var analysisResult = result.AnalysisResult;
+
+ writer.WriteInt32(analysisResult.Count);
+ foreach (var kv in analysisResult)
+ {
+ writer.WriteString(kv.Key);
+
+ Serialize(writer, diagnosticSerializer, kv.Value.SyntaxLocals, cancellationToken);
+ Serialize(writer, diagnosticSerializer, kv.Value.SemanticLocals, cancellationToken);
+ Serialize(writer, diagnosticSerializer, kv.Value.NonLocals, cancellationToken);
+
+ diagnosticSerializer.WriteTo(writer, kv.Value.Others, cancellationToken);
+ }
+
+ var telemetryInfo = result.TelemetryInfo;
+
+ writer.WriteInt32(telemetryInfo.Count);
+ foreach (var kv in telemetryInfo)
+ {
+ writer.WriteString(kv.Key);
+ Serialize(writer, kv.Value, cancellationToken);
+ }
+
+ var exceptions = result.Exceptions;
+
+ writer.WriteInt32(exceptions.Count);
+ foreach (var kv in exceptions)
+ {
+ writer.WriteString(kv.Key);
+ diagnosticSerializer.WriteTo(writer, kv.Value, cancellationToken);
+ }
+ }
+
+ public static DiagnosticAnalysisResultMap Deserialize(
+ ObjectReader reader, IDictionary analyzerMap, Project project, VersionStamp version, CancellationToken cancellationToken)
+ {
+ var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
+
+ var analysisMap = ImmutableDictionary.CreateBuilder();
+
+ var analysisCount = reader.ReadInt32();
+ for (var i = 0; i < analysisCount; i++)
+ {
+ var analyzer = analyzerMap[reader.ReadString()];
+
+ var syntaxLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
+ var semanticLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
+ var nonLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
+
+ var others = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);
+
+ var analysisResult = new DiagnosticAnalysisResult(
+ project.Id, version,
+ syntaxLocalMap, semanticLocalMap, nonLocalMap, others,
+ documentIds: null, fromBuild: false);
+
+ analysisMap.Add(analyzer, analysisResult);
+ }
+
+ var telemetryMap = ImmutableDictionary.CreateBuilder();
+
+ var telemetryCount = reader.ReadInt32();
+ for (var i = 0; i < telemetryCount; i++)
+ {
+ var analyzer = analyzerMap[reader.ReadString()];
+ var telemetryInfo = Deserialize(reader, cancellationToken);
+
+ telemetryMap.Add(analyzer, telemetryInfo);
+ }
+
+ var exceptionMap = ImmutableDictionary.CreateBuilder>();
+
+ var exceptionCount = reader.ReadInt32();
+ for (var i = 0; i < exceptionCount; i++)
+ {
+ var analyzer = analyzerMap[reader.ReadString()];
+ var exceptions = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);
+
+ exceptionMap.Add(analyzer, exceptions);
+ }
+
+ return DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable(), exceptionMap.ToImmutable());
+ }
+
+ private static void Serialize(
+ ObjectWriter writer,
+ DiagnosticDataSerializer serializer,
+ ImmutableDictionary> diagnostics,
+ CancellationToken cancellationToken)
+ {
+ writer.WriteInt32(diagnostics.Count);
+ foreach (var kv in diagnostics)
+ {
+ Serializer.Serialize(kv.Key, writer, cancellationToken);
+ serializer.WriteTo(writer, kv.Value, cancellationToken);
+ }
+ }
+
+ private static ImmutableDictionary> Deserialize(
+ ObjectReader reader,
+ DiagnosticDataSerializer serializer,
+ Project project,
+ CancellationToken cancellationToken)
+ {
+ var count = reader.ReadInt32();
+ var map = ImmutableDictionary.CreateBuilder>();
+ for (var i = 0; i < count; i++)
+ {
+ var documentId = Serializer.DeserializeDocumentId(reader, cancellationToken);
+ var diagnostics = serializer.ReadFrom(reader, project.GetDocument(documentId), cancellationToken);
+
+ map.Add(documentId, diagnostics);
+ }
+
+ return map.ToImmutable();
+ }
+
+ private static void Serialize(ObjectWriter writer, AnalyzerTelemetryInfo telemetryInfo, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ writer.WriteInt32(telemetryInfo.CompilationStartActionsCount);
+ writer.WriteInt32(telemetryInfo.CompilationEndActionsCount);
+ writer.WriteInt32(telemetryInfo.CompilationActionsCount);
+ writer.WriteInt32(telemetryInfo.SyntaxTreeActionsCount);
+ writer.WriteInt32(telemetryInfo.SemanticModelActionsCount);
+ writer.WriteInt32(telemetryInfo.SymbolActionsCount);
+ writer.WriteInt32(telemetryInfo.SyntaxNodeActionsCount);
+ writer.WriteInt32(telemetryInfo.CodeBlockStartActionsCount);
+ writer.WriteInt32(telemetryInfo.CodeBlockEndActionsCount);
+ writer.WriteInt32(telemetryInfo.CodeBlockActionsCount);
+ writer.WriteInt32(telemetryInfo.OperationActionsCount);
+ writer.WriteInt32(telemetryInfo.OperationBlockActionsCount);
+ writer.WriteInt32(telemetryInfo.OperationBlockStartActionsCount);
+ writer.WriteInt32(telemetryInfo.OperationBlockEndActionsCount);
+ writer.WriteInt64(telemetryInfo.ExecutionTime.Ticks);
+ }
+
+ private static AnalyzerTelemetryInfo Deserialize(ObjectReader reader, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var compilationStartActionsCount = reader.ReadInt32();
+ var compilationEndActionsCount = reader.ReadInt32();
+ var compilationActionsCount = reader.ReadInt32();
+ var syntaxTreeActionsCount = reader.ReadInt32();
+ var semanticModelActionsCount = reader.ReadInt32();
+ var symbolActionsCount = reader.ReadInt32();
+ var syntaxNodeActionsCount = reader.ReadInt32();
+ var codeBlockStartActionsCount = reader.ReadInt32();
+ var codeBlockEndActionsCount = reader.ReadInt32();
+ var codeBlockActionsCount = reader.ReadInt32();
+ var operationActionsCount = reader.ReadInt32();
+ var operationBlockActionsCount = reader.ReadInt32();
+ var operationBlockStartActionsCount = reader.ReadInt32();
+ var operationBlockEndActionsCount = reader.ReadInt32();
+ var executionTime = new TimeSpan(reader.ReadInt64());
+
+ return new AnalyzerTelemetryInfo(
+ compilationStartActionsCount,
+ compilationEndActionsCount,
+ compilationActionsCount,
+ syntaxTreeActionsCount,
+ semanticModelActionsCount,
+ symbolActionsCount,
+ syntaxNodeActionsCount,
+ codeBlockStartActionsCount,
+ codeBlockEndActionsCount,
+ codeBlockActionsCount,
+ operationActionsCount,
+ operationBlockStartActionsCount,
+ operationBlockEndActionsCount,
+ operationBlockActionsCount,
+ executionTime);
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/PublicAPI.Shipped.txt b/src/Workspaces/Remote/ServiceHub/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/Workspaces/Remote/ServiceHub/PublicAPI.Unshipped.txt b/src/Workspaces/Remote/ServiceHub/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..335eca8d1cd6df1cb23b33cae0348b427874a0cd
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
@@ -0,0 +1,74 @@
+
+
+
+ CSharp
+
+
+
+
+
+ Debug
+ AnyCPU
+ {80FDDD00-9393-47F7-8BAF-7E87CE011068}
+ Library
+ Microsoft.CodeAnalysis.Remote
+ Microsoft.CodeAnalysis.Remote.ServiceHub
+ v4.6
+ false
+
+
+
+ {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}
+ CodeAnalysis
+
+
+ {DCDA908D-EF5E-494B-ADDC-C26F5FD610CA}
+ Immutable
+
+
+ {2e87fa96-50bb-4607-8676-46521599f998}
+ Workspaces.Desktop
+
+
+ {5F8D2414-064A-4B3A-9B42-8E2A04246BE5}
+ Workspaces
+
+
+ {f822f72a-cc87-4e31-b57d-853f65cbebf3}
+ RemoteWorkspaces
+
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..037311868b2de0eae76e253c65cbc7749e7c5c80
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs
@@ -0,0 +1,16 @@
+// 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.IO;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ // root level service for all Roslyn services
+ internal partial class CodeAnalysisService : ServiceHubJsonRpcServiceBase
+ {
+ public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) :
+ base(stream, serviceProvider)
+ {
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_Diagnostics.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_Diagnostics.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7199f7b5191e7c3e3eb433694ed38efa03f86df0
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_Diagnostics.cs
@@ -0,0 +1,80 @@
+// 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.IO;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Execution;
+using Microsoft.CodeAnalysis.Remote.Diagnostics;
+using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ // root level service for all Roslyn services
+ internal partial class CodeAnalysisService
+ {
+ ///
+ /// This is top level entry point for diagnostic calculation from client (VS).
+ ///
+ /// This will be called by ServiceHub/JsonRpc framework
+ ///
+ public async Task CalculateDiagnosticsAsync(DiagnosticArguments arguments, byte[] solutionChecksum, string streamName)
+ {
+ try
+ {
+ // entry point for diagnostic service
+ var solution = await RoslynServices.SolutionService.GetSolutionAsync(new Checksum(solutionChecksum), CancellationToken).ConfigureAwait(false);
+ var projectId = arguments.GetProjectId();
+ var analyzers = await GetHostAnalyzerReferences(arguments.GetHostAnalyzerChecksums()).ConfigureAwait(false);
+
+ var result = await (new DiagnosticComputer(solution.GetProject(projectId))).GetDiagnosticsAsync(
+ analyzers, arguments.AnalyzerIds, arguments.ReportSuppressedDiagnostics, arguments.LogAnalyzerExecutionTime, CancellationToken).ConfigureAwait(false);
+
+ await SerializeDiagnosticResultAsync(streamName, result).ConfigureAwait(false);
+ }
+ catch (IOException)
+ {
+ // stream to send over result has closed before we
+ // had chance to check cancellation
+ }
+ catch (OperationCanceledException)
+ {
+ // rpc connection has closed.
+ // this can happen if client side cancelled the
+ // operation
+ }
+ }
+
+ private async Task> GetHostAnalyzerReferences(IEnumerable checksums)
+ {
+ var analyzers = new List();
+ foreach (var checksum in checksums)
+ {
+ analyzers.Add(await RoslynServices.AssetService.GetAssetAsync(checksum, CancellationToken).ConfigureAwait(false));
+ }
+
+ return analyzers;
+ }
+
+ private async Task SerializeDiagnosticResultAsync(string streamName, DiagnosticAnalysisResultMap result)
+ {
+ using (var stream = new ClientDirectStream(streamName))
+ {
+ await stream.ConnectAsync(CancellationToken).ConfigureAwait(false);
+
+ using (var writer = new ObjectWriter(stream))
+ {
+ DiagnosticResultSerializer.Serialize(writer, result, CancellationToken);
+ }
+
+ await stream.FlushAsync(CancellationToken).ConfigureAwait(false);
+
+ // TODO: think of a way this is not needed
+ // wait for the other side to finish reading data I sent over
+ stream.WaitForServer();
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c00fb48be2a51570f19fc7b5624397371d7f6843
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
@@ -0,0 +1,37 @@
+// 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.IO;
+using System.Threading;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ ///
+ /// Service that client will connect to to make service hub alive even when there is
+ /// no other people calling service hub.
+ ///
+ /// basically, this is used to manage lifetime of the service hub.
+ ///
+ internal class RemoteHostService : ServiceHubJsonRpcServiceBase
+ {
+ private string _host;
+
+ public RemoteHostService(Stream stream, IServiceProvider serviceProvider) :
+ base(stream, serviceProvider)
+ {
+ // this service provide a way for client to make sure remote host is alive
+ }
+
+ public string Connect(string host)
+ {
+ var existing = Interlocked.CompareExchange(ref _host, host, null);
+
+ if (existing != null && existing != host)
+ {
+ LogError($"{host} is given for {existing}");
+ }
+
+ return _host;
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/ServiceHubJsonRpcServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubJsonRpcServiceBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..25bf1c33a30013ae52684a45dcc1f2ad9d65b107
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubJsonRpcServiceBase.cs
@@ -0,0 +1,51 @@
+// 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 StreamJsonRpc;
+using System;
+using System.IO;
+using System.Threading;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ internal abstract class ServiceHubJsonRpcServiceBase : ServiceHubServiceBase
+ {
+ private readonly CancellationTokenSource _source;
+
+ protected readonly JsonRpc Rpc;
+ protected readonly CancellationToken CancellationToken;
+
+ public ServiceHubJsonRpcServiceBase(Stream stream, IServiceProvider serviceProvider) : base(stream, serviceProvider)
+ {
+ _source = new CancellationTokenSource();
+ CancellationToken = _source.Token;
+
+ Rpc = JsonRpc.Attach(stream, this);
+ Rpc.Disconnected += OnRpcDisconnected;
+ }
+
+ protected virtual void OnDisconnected(JsonRpcDisconnectedEventArgs e)
+ {
+ // do nothing
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ Rpc.Dispose();
+ }
+
+ private void OnRpcDisconnected(object sender, JsonRpcDisconnectedEventArgs e)
+ {
+ // raise cancellation
+ _source.Cancel();
+
+ OnDisconnected(e);
+
+ if (e.Reason != DisconnectedReason.Disposed)
+ {
+ LogError($"Client stream disconnected unexpectedly: {e.Exception?.GetType().Name} {e.Exception?.Message}");
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/ServiceHubServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubServiceBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae67767f35c0ca3991e7182c5a7db29632855137
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubServiceBase.cs
@@ -0,0 +1,51 @@
+// 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.Diagnostics;
+using System.IO;
+using System.Threading;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ // TODO: all service hub service should be extract to interface so that it can support multiple hosts.
+ // right now, tightly coupled to service hub
+ internal abstract class ServiceHubServiceBase : IDisposable
+ {
+ private static int s_instanceId = 0;
+
+ protected readonly int InstanceId = 0;
+ protected readonly TraceSource Logger;
+ protected readonly Stream Stream;
+
+ protected ServiceHubServiceBase(Stream stream, IServiceProvider serviceProvider)
+ {
+ InstanceId = Interlocked.Add(ref s_instanceId, 1);
+
+ Logger = (TraceSource)serviceProvider.GetService(typeof(TraceSource));
+ Logger.TraceInformation($"{DebugInstanceString} Service instance created");
+
+ Stream = stream;
+ }
+
+ protected string DebugInstanceString => $"{GetType().ToString()} ({InstanceId})";
+
+ protected virtual void Dispose(bool disposing)
+ {
+ // do nothing here
+ }
+
+ protected void LogError(string message)
+ {
+ Logger.TraceEvent(TraceEventType.Error, 0, $"{DebugInstanceString} : " + message);
+ }
+
+ public void Dispose()
+ {
+ Stream.Dispose();
+
+ Dispose(false);
+
+ Logger.TraceInformation($"{DebugInstanceString} Service instance disposed");
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/ServiceHubSnapshotService.cs b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubSnapshotService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3f89824b03ace571781af764f2f63cdbadafb8fd
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/ServiceHubSnapshotService.cs
@@ -0,0 +1,90 @@
+// 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.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Execution;
+using Roslyn.Utilities;
+using StreamJsonRpc;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ ///
+ /// Snapshot service in service hub side.
+ ///
+ /// this service will be used to move over snapshot data from client to service hub
+ ///
+ internal class ServiceHubSnapshotService : ServiceHubJsonRpcServiceBase
+ {
+ private readonly AssetSource _source;
+
+ public ServiceHubSnapshotService(Stream stream, IServiceProvider serviceProvider) :
+ base(stream, serviceProvider)
+ {
+ _source = new ServiceHubAssetSource(Rpc, Logger, CancellationToken);
+ }
+
+ protected override void OnDisconnected(JsonRpcDisconnectedEventArgs e)
+ {
+ _source.Done();
+ }
+
+ private class ServiceHubAssetSource : AssetSource
+ {
+ private readonly JsonRpc _rpc;
+ private readonly TraceSource _logger;
+ private readonly CancellationToken _assetChannelCancellationToken;
+
+ public ServiceHubAssetSource(JsonRpc rpc, TraceSource logger, CancellationToken assetChannelCancellationToken) :
+ base()
+ {
+ _rpc = rpc;
+ _logger = logger;
+ _assetChannelCancellationToken = assetChannelCancellationToken;
+ }
+
+ public override async Task RequestAssetAsync(int serviceId, Checksum checksum, CancellationToken callerCancellationToken)
+ {
+ // it should succeed as long as matching VS is alive
+ // TODO: add logging mechanism using Logger
+
+ // this can be called in two ways.
+ // 1. Connection to get asset is closed (the asset source we were using is disconnected - _assetChannelCancellationToken)
+ // if this asset source's channel is closed, service will move to next asset source to get the asset as long as callerCancellationToken
+ // is not cancelled
+ //
+ // 2. Request to required this asset has cancelled. (callerCancellationToken)
+ using (var mergedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(_assetChannelCancellationToken, callerCancellationToken))
+ {
+ await _rpc.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync,
+ new object[] { serviceId, checksum.ToArray() },
+ (s, c) => ReadAssetAsync(s, _logger, serviceId, checksum, c), mergedCancellationToken.Token).ConfigureAwait(false);
+ }
+ }
+
+ private static Task ReadAssetAsync(
+ Stream stream, TraceSource logger, int serviceId, Checksum checksum, CancellationToken cancellationToken)
+ {
+ using (var reader = new ObjectReader(stream))
+ {
+ var responseServiceId = reader.ReadInt32();
+ Contract.ThrowIfFalse(serviceId == responseServiceId);
+
+ var responseChecksum = new Checksum(reader.ReadArray());
+ Contract.ThrowIfFalse(checksum == responseChecksum);
+
+ var kind = reader.ReadString();
+
+ // in service hub, cancellation means simply closed stream
+ var @object = RoslynServices.AssetService.Deserialize