diff --git a/eng/Versions.props b/eng/Versions.props
index c8deabcd0bb4d..6c648e85f4e34 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -173,8 +173,8 @@
12.0.30110
12.1.30328
16.0.0
- 16.7.53
- 16.6.13
+ 16.7.54
+ 16.7.54
16.6.29925.50
15.5.31
2.8.0
@@ -246,7 +246,7 @@
create a test insertion in Visual Studio to validate.
-->
12.0.2
- 2.6.21-alpha
+ 2.6.86-alpha
5.0.0-preview.8.20407.11
5.0.0-preview.8.20407.11
1.1.1
diff --git a/eng/targets/Services.props b/eng/targets/Services.props
index 0c216727f9b27..972b09b076ea1 100644
--- a/eng/targets/Services.props
+++ b/eng/targets/Services.props
@@ -11,15 +11,26 @@
Note that brokered services must be defined in Microsoft.VisualStudio service namespace in order to be considered first party.
-->
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs
index 1e4968e80cc1d..62eca7c0b1910 100644
--- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs
+++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs
@@ -5,114 +5,136 @@
#nullable enable
using System;
+using System.Runtime.Serialization;
namespace Microsoft.CodeAnalysis.Diagnostics.Telemetry
{
///
/// Contains telemetry info for a specific analyzer, such as count of registered actions, the total execution time, etc.
///
+ [DataContract]
public sealed class AnalyzerTelemetryInfo
{
///
/// Count of registered compilation start actions.
///
- public int CompilationStartActionsCount { get; set; } = 0;
+ [DataMember(Order = 0)]
+ public int CompilationStartActionsCount { get; set; }
///
/// Count of registered compilation end actions.
///
- public int CompilationEndActionsCount { get; set; } = 0;
+ [DataMember(Order = 1)]
+ public int CompilationEndActionsCount { get; set; }
///
/// Count of registered compilation actions.
///
- public int CompilationActionsCount { get; set; } = 0;
+ [DataMember(Order = 2)]
+ public int CompilationActionsCount { get; set; }
///
/// Count of registered syntax tree actions.
///
- public int SyntaxTreeActionsCount { get; set; } = 0;
+ [DataMember(Order = 3)]
+ public int SyntaxTreeActionsCount { get; set; }
///
/// Count of registered additional file actions.
///
- public int AdditionalFileActionsCount { get; set; } = 0;
+ [DataMember(Order = 4)]
+ public int AdditionalFileActionsCount { get; set; }
///
/// Count of registered semantic model actions.
///
- public int SemanticModelActionsCount { get; set; } = 0;
+ [DataMember(Order = 5)]
+ public int SemanticModelActionsCount { get; set; }
///
/// Count of registered symbol actions.
///
- public int SymbolActionsCount { get; set; } = 0;
+ [DataMember(Order = 6)]
+ public int SymbolActionsCount { get; set; }
///
/// Count of registered symbol start actions.
///
- public int SymbolStartActionsCount { get; set; } = 0;
+ [DataMember(Order = 7)]
+ public int SymbolStartActionsCount { get; set; }
///
/// Count of registered symbol end actions.
///
- public int SymbolEndActionsCount { get; set; } = 0;
+ [DataMember(Order = 8)]
+ public int SymbolEndActionsCount { get; set; }
///
/// Count of registered syntax node actions.
///
- public int SyntaxNodeActionsCount { get; set; } = 0;
+ [DataMember(Order = 9)]
+ public int SyntaxNodeActionsCount { get; set; }
///
/// Count of registered code block start actions.
///
- public int CodeBlockStartActionsCount { get; set; } = 0;
+ [DataMember(Order = 10)]
+ public int CodeBlockStartActionsCount { get; set; }
///
/// Count of registered code block end actions.
///
- public int CodeBlockEndActionsCount { get; set; } = 0;
+ [DataMember(Order = 11)]
+ public int CodeBlockEndActionsCount { get; set; }
///
/// Count of registered code block actions.
///
- public int CodeBlockActionsCount { get; set; } = 0;
+ [DataMember(Order = 12)]
+ public int CodeBlockActionsCount { get; set; }
///
/// Count of registered operation actions.
///
- public int OperationActionsCount { get; set; } = 0;
+ [DataMember(Order = 13)]
+ public int OperationActionsCount { get; set; }
///
/// Count of registered operation block start actions.
///
- public int OperationBlockStartActionsCount { get; set; } = 0;
+ [DataMember(Order = 14)]
+ public int OperationBlockStartActionsCount { get; set; }
///
/// Count of registered operation block end actions.
///
- public int OperationBlockEndActionsCount { get; set; } = 0;
+ [DataMember(Order = 15)]
+ public int OperationBlockEndActionsCount { get; set; }
///
/// Count of registered operation block actions.
///
- public int OperationBlockActionsCount { get; set; } = 0;
+ [DataMember(Order = 16)]
+ public int OperationBlockActionsCount { get; set; }
///
/// Count of registered suppression actions.
/// This is the same as count of s as each suppressor
/// has a single suppression action, i.e. .
///
- public int SuppressionActionsCount { get; set; } = 0;
+ [DataMember(Order = 17)]
+ public int SuppressionActionsCount { get; set; }
///
/// Total execution time.
///
+ [DataMember(Order = 18)]
public TimeSpan ExecutionTime { get; set; } = TimeSpan.Zero;
///
/// Gets a value indicating whether the analyzer supports concurrent execution.
///
+ [DataMember(Order = 19)]
public bool Concurrent { get; set; }
internal AnalyzerTelemetryInfo(AnalyzerActionCounts actionCounts, int suppressionActionCounts, TimeSpan executionTime)
diff --git a/src/Compilers/Core/Portable/Text/TextChange.cs b/src/Compilers/Core/Portable/Text/TextChange.cs
index cff2b5041ce61..6da2b595ecbb4 100644
--- a/src/Compilers/Core/Portable/Text/TextChange.cs
+++ b/src/Compilers/Core/Portable/Text/TextChange.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
@@ -15,16 +16,19 @@ namespace Microsoft.CodeAnalysis.Text
///
/// Describes a single change when a particular span is replaced with a new text.
///
+ [DataContract]
public readonly struct TextChange : IEquatable
{
///
/// The original span of the changed text.
///
+ [DataMember(Order = 0)]
public TextSpan Span { get; }
///
/// The new text.
///
+ [DataMember(Order = 1)]
public string? NewText { get; }
///
diff --git a/src/Compilers/Core/Portable/Text/TextSpan.cs b/src/Compilers/Core/Portable/Text/TextSpan.cs
index fed431a15dad0..f76f2e587b9c2 100644
--- a/src/Compilers/Core/Portable/Text/TextSpan.cs
+++ b/src/Compilers/Core/Portable/Text/TextSpan.cs
@@ -5,6 +5,7 @@
#nullable enable
using System;
+using System.Runtime.Serialization;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Text
@@ -13,6 +14,7 @@ namespace Microsoft.CodeAnalysis.Text
/// Immutable abstract representation of a span of text. For example, in an error diagnostic that reports a
/// location, it could come from a parsed string, text from a tool editor buffer, etc.
///
+ [DataContract]
public readonly struct TextSpan : IEquatable, IComparable
{
///
@@ -38,6 +40,7 @@ public TextSpan(int start, int length)
///
/// Start point of the span.
///
+ [DataMember(Order = 0)]
public int Start { get; }
///
@@ -48,6 +51,7 @@ public TextSpan(int start, int length)
///
/// Length of the span.
///
+ [DataMember(Order = 1)]
public int Length { get; }
///
diff --git a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs
index b513b76c16ef0..6e36565be9d8b 100644
--- a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs
+++ b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesLSPService.cs
@@ -15,8 +15,7 @@ internal class CSharpFindUsagesLSPService : AbstractFindUsagesService
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- public CSharpFindUsagesLSPService(IThreadingContext threadingContext)
- : base(threadingContext)
+ public CSharpFindUsagesLSPService()
{
}
}
diff --git a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs
index f4f1ce49b1936..a56394135ec9d 100644
--- a/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs
+++ b/src/EditorFeatures/CSharp/FindUsages/CSharpFindUsagesService.cs
@@ -17,8 +17,7 @@ internal class CSharpFindUsagesService : AbstractFindUsagesService
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
- public CSharpFindUsagesService(IThreadingContext threadingContext)
- : base(threadingContext)
+ public CSharpFindUsagesService()
{
}
}
diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs
index 3f18c3565f2b2..fe8be5b6336f7 100644
--- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs
+++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs
@@ -62,7 +62,7 @@ public async Task TestSearchPackageSingleName()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(
NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
@@ -93,7 +93,7 @@ public async Task TestSearchPackageMultipleNames()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(
NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
@@ -122,7 +122,7 @@ public async Task TestMissingIfPackageAlreadyInstalled()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(
NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
@@ -148,7 +148,7 @@ public async Task TestOptionsOffered()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(
NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")));
@@ -192,7 +192,7 @@ public async Task TestInstallGetsCalledNoVersion()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(
NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
@@ -226,7 +226,7 @@ public async Task TestInstallGetsCalledWithVersion()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
@@ -260,7 +260,7 @@ public async Task TestFailedInstallRollsBackFile()
var packageServiceMock = new Mock(MockBehavior.Strict);
packageServiceMock.Setup(s => s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny()))
- .Returns(Task.FromResult>(new List()));
+ .Returns(new ValueTask>(ImmutableArray.Empty));
packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny()))
.Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")));
@@ -276,17 +276,18 @@ await TestInRegularAndScriptAsync(
installerServiceMock.Verify();
}
- private static Task> CreateSearchResult(
+ private static ValueTask> CreateSearchResult(
string packageName, string typeName, ImmutableArray containingNamespaceNames)
{
return CreateSearchResult(new PackageWithTypeResult(
- packageName: packageName, typeName: typeName, version: null,
- rank: 0, containingNamespaceNames: containingNamespaceNames));
+ packageName: packageName, rank: 0, typeName: typeName,
+ version: null, containingNamespaceNames: containingNamespaceNames));
}
- private static Task> CreateSearchResult(params PackageWithTypeResult[] results)
- => Task.FromResult>(ImmutableArray.Create(results));
+ private static ValueTask> CreateSearchResult(params PackageWithTypeResult[] results)
+ => new(ImmutableArray.Create(results));
- private static ImmutableArray CreateNameParts(params string[] parts) => parts.ToImmutableArray();
+ private static ImmutableArray CreateNameParts(params string[] parts)
+ => parts.ToImmutableArray();
}
}
diff --git a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs
index a9c7b412365df..8acf07e2d45a8 100644
--- a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs
+++ b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs
@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Extensions;
+using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
@@ -25,21 +26,40 @@ public partial class PreviewTests
public async Task TestExceptionInComputePreview()
{
using var workspace = CreateWorkspaceFromOptions("class D {}", new TestParameters());
+
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
await GetPreview(workspace, new ErrorCases.ExceptionInCodeAction());
+ Assert.True(errorReported);
}
[WpfFact]
public void TestExceptionInDisplayText()
{
using var workspace = CreateWorkspaceFromOptions("class D {}", new TestParameters());
+
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
DisplayText(workspace, new ErrorCases.ExceptionInCodeAction());
+ Assert.True(errorReported);
}
[WpfFact]
public async Task TestExceptionInActionSets()
{
using var workspace = CreateWorkspaceFromOptions("class D {}", new TestParameters());
+
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
await ActionSets(workspace, new ErrorCases.ExceptionInCodeAction());
+
+ Assert.True(errorReported);
}
private static async Task GetPreview(TestWorkspace workspace, CodeRefactoringProvider provider)
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
index 11ce232700ed1..d015f0cc1b3fe 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
@@ -37,20 +37,20 @@ public CancellationToken CancellationToken
public IStreamingProgressTracker ProgressTracker
=> _underlyingContext.ProgressTracker;
- public Task ReportMessageAsync(string message)
+ public ValueTask ReportMessageAsync(string message)
=> _underlyingContext.ReportMessageAsync(message);
- public Task SetSearchTitleAsync(string title)
+ public ValueTask SetSearchTitleAsync(string title)
=> _underlyingContext.SetSearchTitleAsync(title);
- public Task OnReferenceFoundAsync(SourceReferenceItem reference)
+ public ValueTask OnReferenceFoundAsync(SourceReferenceItem reference)
=> _underlyingContext.OnReferenceFoundAsync(reference);
[Obsolete("Use ProgressTracker instead", error: false)]
- public Task ReportProgressAsync(int current, int maximum)
+ public ValueTask ReportProgressAsync(int current, int maximum)
=> _underlyingContext.ReportProgressAsync(current, maximum);
- public Task OnDefinitionFoundAsync(DefinitionItem definition)
+ public ValueTask OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (_gate)
{
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
index 0ccbc0881c0aa..d3ac21dece7cb 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
@@ -36,7 +36,7 @@ public FindLiteralsProgressAdapter(
_definition = definition;
}
- public async Task OnReferenceFoundAsync(Document document, TextSpan span)
+ public async ValueTask OnReferenceFoundAsync(Document document, TextSpan span)
{
var documentSpan = await ClassifiedSpansAndHighlightSpanFactory.GetClassifiedDocumentSpanAsync(
document, span, _context.CancellationToken).ConfigureAwait(false);
@@ -82,16 +82,16 @@ public FindReferencesProgressAdapter(
// Do nothing functions. The streaming far service doesn't care about
// any of these.
- public Task OnStartedAsync() => Task.CompletedTask;
- public Task OnCompletedAsync() => Task.CompletedTask;
- public Task OnFindInDocumentStartedAsync(Document document) => Task.CompletedTask;
- public Task OnFindInDocumentCompletedAsync(Document document) => Task.CompletedTask;
+ public ValueTask OnStartedAsync() => default;
+ public ValueTask OnCompletedAsync() => default;
+ public ValueTask OnFindInDocumentStartedAsync(Document document) => default;
+ public ValueTask OnFindInDocumentCompletedAsync(Document document) => default;
// More complicated forwarding functions. These need to map from the symbols
// used by the FAR engine to the INavigableItems used by the streaming FAR
// feature.
- private async Task GetDefinitionItemAsync(ISymbol definition)
+ private async ValueTask GetDefinitionItemAsync(ISymbol definition)
{
var cancellationToken = _context.CancellationToken;
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
@@ -112,13 +112,13 @@ private async Task GetDefinitionItemAsync(ISymbol definition)
}
}
- public async Task OnDefinitionFoundAsync(ISymbol definition)
+ public async ValueTask OnDefinitionFoundAsync(ISymbol definition)
{
var definitionItem = await GetDefinitionItemAsync(definition).ConfigureAwait(false);
await _context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false);
}
- public async Task OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location)
+ public async ValueTask OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location)
{
var definitionItem = await GetDefinitionItemAsync(definition).ConfigureAwait(false);
var referenceItem = await location.TryCreateSourceReferenceItemAsync(
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
index 9c53c2e3bb257..9f011155b934c 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
@@ -10,9 +10,5 @@ namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal abstract partial class AbstractFindUsagesService : IFindUsagesService, IFindUsagesLSPService
{
- private readonly IThreadingContext _threadingContext;
-
- protected AbstractFindUsagesService(IThreadingContext threadingContext)
- => _threadingContext = threadingContext;
}
}
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs
index cbe6ed362d654..92042144e18a4 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs
@@ -51,15 +51,11 @@ public static async Task FindImplementationsAsync(
// results as it finds them. When we hear about results we'll forward them to
// the 'progress' parameter which will then update the UI.
var serverCallback = new FindUsagesServerCallback(solution, context);
+ var symbolAndProjectId = SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken);
- await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteFindUsagesService.FindImplementationsAsync),
+ await client.TryInvokeAsync(
solution,
- new object[]
- {
- SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken),
- },
+ (service, solutionInfo, cancellationToken) => service.FindImplementationsAsync(solutionInfo, symbolAndProjectId, cancellationToken),
serverCallback,
cancellationToken).ConfigureAwait(false);
}
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs
index 8aca444539046..8b84ca2550f64 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs
@@ -114,7 +114,7 @@ public static async Task FindSymbolReferencesAsync(
await context.SetSearchTitleAsync(string.Format(EditorFeaturesResources._0_references,
FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false);
- var options = FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol);
+ var options = FindSymbols.FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol);
// Now call into the underlying FAR engine to find reference. The FAR
// engine will push results into the 'progress' instance passed into it.
@@ -138,16 +138,11 @@ public static async Task FindReferencesAsync(
// results as it finds them. When we hear about results we'll forward them to
// the 'progress' parameter which will then update the UI.
var serverCallback = new FindUsagesServerCallback(solution, context);
+ var symbolAndProjectId = SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken);
- await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteFindUsagesService.FindReferencesAsync),
+ _ = await client.TryInvokeAsync(
solution,
- new object[]
- {
- SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken),
- SerializableFindReferencesSearchOptions.Dehydrate(options),
- },
+ (service, solutionInfo, cancellationToken) => service.FindReferencesAsync(solutionInfo, symbolAndProjectId, options, cancellationToken),
serverCallback,
cancellationToken).ConfigureAwait(false);
}
diff --git a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs b/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs
index 3b07a1c37dc4b..1133af77c5313 100644
--- a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs
+++ b/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs
@@ -17,19 +17,19 @@ internal abstract class FindUsagesContext : IFindUsagesContext
protected FindUsagesContext()
=> this.ProgressTracker = new StreamingProgressTracker(this.ReportProgressAsync);
- public virtual Task ReportMessageAsync(string message) => Task.CompletedTask;
+ public virtual ValueTask ReportMessageAsync(string message) => default;
- public virtual Task SetSearchTitleAsync(string title) => Task.CompletedTask;
+ public virtual ValueTask SetSearchTitleAsync(string title) => default;
- public virtual Task OnCompletedAsync() => Task.CompletedTask;
+ public virtual ValueTask OnCompletedAsync() => default;
- public virtual Task OnDefinitionFoundAsync(DefinitionItem definition) => Task.CompletedTask;
+ public virtual ValueTask OnDefinitionFoundAsync(DefinitionItem definition) => default;
- public virtual Task OnReferenceFoundAsync(SourceReferenceItem reference) => Task.CompletedTask;
+ public virtual ValueTask OnReferenceFoundAsync(SourceReferenceItem reference) => default;
- protected virtual Task ReportProgressAsync(int current, int maximum) => Task.CompletedTask;
+ protected virtual ValueTask ReportProgressAsync(int current, int maximum) => default;
- Task IFindUsagesContext.ReportProgressAsync(int current, int maximum)
+ ValueTask IFindUsagesContext.ReportProgressAsync(int current, int maximum)
=> ReportProgressAsync(current, maximum);
}
}
diff --git a/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs
deleted file mode 100644
index 01fb1dcb8c309..0000000000000
--- a/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs
+++ /dev/null
@@ -1,190 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.FindUsages;
-using Microsoft.CodeAnalysis.Remote;
-using Microsoft.CodeAnalysis.Text;
-using Roslyn.Utilities;
-
-namespace Microsoft.CodeAnalysis.Editor.FindUsages
-{
- internal interface IRemoteFindUsagesService
- {
- Task FindReferencesAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId symbolAndProjectIdArg,
- SerializableFindReferencesSearchOptions options,
- CancellationToken cancellationToken);
-
- Task FindImplementationsAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId symbolAndProjectIdArg,
- CancellationToken cancellationToken);
- }
-
- internal class FindUsagesServerCallback
- {
- private readonly Solution _solution;
- private readonly IFindUsagesContext _context;
- private readonly Dictionary _idToDefinition = new Dictionary();
-
- public FindUsagesServerCallback(Solution solution, IFindUsagesContext context)
- {
- _solution = solution;
- _context = context;
- }
-
- public Task AddItemsAsync(int count)
- => _context.ProgressTracker.AddItemsAsync(count);
-
- public Task ItemCompletedAsync()
- => _context.ProgressTracker.ItemCompletedAsync();
-
- public Task ReportMessageAsync(string message)
- => _context.ReportMessageAsync(message);
-
- [Obsolete]
- public Task ReportProgressAsync(int current, int maximum)
- => _context.ReportProgressAsync(current, maximum);
-
- public Task SetSearchTitleAsync(string title)
- => _context.SetSearchTitleAsync(title);
-
- public Task OnDefinitionFoundAsync(SerializableDefinitionItem definition)
- {
- var id = definition.Id;
- var rehydrated = definition.Rehydrate(_solution);
-
- lock (_idToDefinition)
- {
- _idToDefinition.Add(id, rehydrated);
- }
-
- return _context.OnDefinitionFoundAsync(rehydrated);
- }
-
- public Task OnReferenceFoundAsync(SerializableSourceReferenceItem reference)
- => _context.OnReferenceFoundAsync(reference.Rehydrate(_solution, GetDefinition(reference.DefinitionId)));
-
- private DefinitionItem GetDefinition(int definitionId)
- {
- lock (_idToDefinition)
- {
- Contract.ThrowIfFalse(_idToDefinition.ContainsKey(definitionId));
- return _idToDefinition[definitionId];
- }
- }
- }
-
- internal class SerializableDocumentSpan
- {
- public DocumentId DocumentId;
- public TextSpan SourceSpan;
-
- public static SerializableDocumentSpan Dehydrate(DocumentSpan documentSpan)
- => new SerializableDocumentSpan
- {
- DocumentId = documentSpan.Document.Id,
- SourceSpan = documentSpan.SourceSpan,
- };
-
- public DocumentSpan Rehydrate(Solution solution)
- => new DocumentSpan(solution.GetDocument(DocumentId), SourceSpan);
- }
-
- internal class SerializableTaggedText
- {
- public string Tag;
- public string Text;
- public TaggedTextStyle Style;
- public string NavigationTarget;
- public string NavigationHint;
-
- public static SerializableTaggedText Dehydrate(TaggedText text)
- => new SerializableTaggedText
- {
- Tag = text.Tag,
- Text = text.Text,
- Style = text.Style,
- NavigationTarget = text.NavigationTarget,
- NavigationHint = text.NavigationHint,
- };
-
- public TaggedText Rehydrate()
- => new TaggedText(Tag, Text, Style, NavigationTarget, NavigationHint);
- }
-
- internal class SerializableDefinitionItem
- {
- public int Id;
- public string[] Tags;
- public SerializableTaggedText[] DisplayParts;
- public SerializableTaggedText[] NameDisplayParts;
- public SerializableTaggedText[] OriginationParts;
- public SerializableDocumentSpan[] SourceSpans;
- public (string key, string value)[] Properties;
- public (string key, string value)[] DisplayableProperties;
- public bool DisplayIfNoReferences;
-
- public static SerializableDefinitionItem Dehydrate(int id, DefinitionItem item)
- => new SerializableDefinitionItem
- {
- Id = id,
- Tags = item.Tags.ToArray(),
- DisplayParts = item.DisplayParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
- NameDisplayParts = item.NameDisplayParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
- OriginationParts = item.OriginationParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
- SourceSpans = item.SourceSpans.Select(ss => SerializableDocumentSpan.Dehydrate(ss)).ToArray(),
- Properties = item.Properties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
- DisplayableProperties = item.DisplayableProperties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
- DisplayIfNoReferences = item.DisplayIfNoReferences,
- };
-
- public DefinitionItem Rehydrate(Solution solution)
- => new DefinitionItem.DefaultDefinitionItem(
- Tags.ToImmutableArray(),
- DisplayParts.SelectAsArray(dp => dp.Rehydrate()),
- NameDisplayParts.SelectAsArray(dp => dp.Rehydrate()),
- OriginationParts.SelectAsArray(dp => dp.Rehydrate()),
- SourceSpans.SelectAsArray(ss => ss.Rehydrate(solution)),
- Properties.ToImmutableDictionary(t => t.key, t => t.value),
- DisplayableProperties.ToImmutableDictionary(t => t.key, t => t.value),
- DisplayIfNoReferences);
- }
-
- internal class SerializableSourceReferenceItem
- {
- public int DefinitionId;
- public SerializableDocumentSpan SourceSpan;
- public SerializableSymbolUsageInfo SymbolUsageInfo;
- public (string Key, string Value)[] AdditionalProperties;
-
- public static SerializableSourceReferenceItem Dehydrate(
- int definitionId, SourceReferenceItem item)
- {
- return new SerializableSourceReferenceItem
- {
- DefinitionId = definitionId,
- SourceSpan = SerializableDocumentSpan.Dehydrate(item.SourceSpan),
- SymbolUsageInfo = SerializableSymbolUsageInfo.Dehydrate(item.SymbolUsageInfo),
- AdditionalProperties = item.AdditionalProperties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
- };
- }
-
- public SourceReferenceItem Rehydrate(Solution solution, DefinitionItem definition)
- {
- return new SourceReferenceItem(
- definition,
- SourceSpan.Rehydrate(solution),
- SymbolUsageInfo.Rehydrate(),
- AdditionalProperties.ToImmutableDictionary(t => t.Key, t => t.Value));
- }
- }
-}
diff --git a/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs b/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs
index 0420585a96f36..c8cf6b849ad90 100644
--- a/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs
+++ b/src/EditorFeatures/Core/FindUsages/SimpleFindUsagesContext.cs
@@ -31,16 +31,16 @@ public SimpleFindUsagesContext(CancellationToken cancellationToken)
public string Message { get; private set; }
public string SearchTitle { get; private set; }
- public override Task ReportMessageAsync(string message)
+ public override ValueTask ReportMessageAsync(string message)
{
Message = message;
- return Task.CompletedTask;
+ return default;
}
- public override Task SetSearchTitleAsync(string title)
+ public override ValueTask SetSearchTitleAsync(string title)
{
SearchTitle = title;
- return Task.CompletedTask;
+ return default;
}
public ImmutableArray GetDefinitions()
@@ -59,24 +59,24 @@ public ImmutableArray GetReferences()
}
}
- public override Task OnDefinitionFoundAsync(DefinitionItem definition)
+ public override ValueTask OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (_gate)
{
_definitionItems.Add(definition);
}
- return Task.CompletedTask;
+ return default;
}
- public override Task OnReferenceFoundAsync(SourceReferenceItem reference)
+ public override ValueTask OnReferenceFoundAsync(SourceReferenceItem reference)
{
lock (_gate)
{
_referenceItems.Add(reference);
}
- return Task.CompletedTask;
+ return default;
}
}
}
diff --git a/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs b/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs
index 83f82e871d8f3..be9eb36935083 100644
--- a/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs
+++ b/src/EditorFeatures/Core/Implementation/Workspaces/EditorErrorReportingService.cs
@@ -12,6 +12,8 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces
{
internal class EditorErrorReportingService : IErrorReportingService
{
+ public string HostDisplayName => "host";
+
public void ShowDetailedErrorInfo(Exception exception)
=> Logger.Log(FunctionId.Extension_Exception, exception.StackTrace);
@@ -23,5 +25,10 @@ public void ShowGlobalErrorInfo(string message, params InfoBarUI[] items)
public void ShowRemoteHostCrashedErrorInfo(Exception? exception)
=> Logger.Log(FunctionId.Extension_Exception, exception?.Message);
+
+ public void ShowFeatureNotAvailableErrorInfo(string message, Exception? exception)
+ {
+ // telemetry has already been reported
+ }
}
}
diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs
index 97cc1a7fb9219..e7795035e3e58 100644
--- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs
+++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs
@@ -13,11 +13,9 @@
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
-using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.VisualStudio.RemoteControl;
-using Roslyn.Utilities;
using static System.FormattableString;
namespace Microsoft.CodeAnalysis.SymbolSearch
@@ -56,19 +54,18 @@ internal partial class SymbolSearchUpdateEngine
private readonly IDatabaseFactoryService _databaseFactoryService;
private readonly Func _reportAndSwallowException;
- private Task LogInfoAsync(string text) => _logService.LogInfoAsync(text);
+ private ValueTask LogInfoAsync(string text, CancellationToken cancellationToken)
+ => _logService.LogInfoAsync(text, cancellationToken);
- private Task LogExceptionAsync(Exception e, string text) => _logService.LogExceptionAsync(e.ToString(), text);
-
- public Task UpdateContinuouslyAsync(string source, string localSettingsDirectory)
- => UpdateContinuouslyAsync(source, localSettingsDirectory, CancellationToken.None);
+ private ValueTask LogExceptionAsync(Exception e, string text, CancellationToken cancellationToken)
+ => _logService.LogExceptionAsync(e.ToString(), text, cancellationToken);
///
/// Cancellation support for the task we use to keep the local database up to date.
/// Currently used only in tests so we can shutdown gracefully. In normal VS+OOP scenarios
/// we don't care about this and we just get torn down when the OOP process goes down.
///
- internal Task UpdateContinuouslyAsync(string source, string localSettingsDirectory, CancellationToken cancellationToken)
+ public ValueTask UpdateContinuouslyAsync(string source, string localSettingsDirectory, CancellationToken cancellationToken)
{
// Only the first thread to try to update this source should succeed
// and cause us to actually begin the update loop.
@@ -78,7 +75,7 @@ internal Task UpdateContinuouslyAsync(string source, string localSettingsDirecto
if (ourSentinel != currentSentinel)
{
// We already have an update loop for this source. Nothing for us to do.
- return Task.CompletedTask;
+ return default;
}
// We were the first ones to try to update this source. Spawn off a task to do
@@ -104,7 +101,7 @@ public Updater(SymbolSearchUpdateEngine service, string source, string localSett
///
/// Internal for testing purposes.
///
- internal async Task UpdateInBackgroundAsync(CancellationToken cancellationToken)
+ internal async ValueTask UpdateInBackgroundAsync(CancellationToken cancellationToken)
{
// We only support this single source currently.
if (_source != NugetOrgSource)
@@ -115,17 +112,17 @@ internal async Task UpdateInBackgroundAsync(CancellationToken cancellationToken)
// Keep on looping until we're told to shut down.
while (!cancellationToken.IsCancellationRequested)
{
- await _service.LogInfoAsync("Starting update").ConfigureAwait(false);
+ await _service.LogInfoAsync("Starting update", cancellationToken).ConfigureAwait(false);
try
{
var delayUntilNextUpdate = await UpdateDatabaseInBackgroundWorkerAsync(cancellationToken).ConfigureAwait(false);
- await _service.LogInfoAsync($"Waiting {delayUntilNextUpdate} until next update").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Waiting {delayUntilNextUpdate} until next update", cancellationToken).ConfigureAwait(false);
await Task.Delay(delayUntilNextUpdate, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
- await _service.LogInfoAsync("Update canceled. Ending update loop").ConfigureAwait(false);
+ await _service.LogInfoAsync("Update canceled. Ending update loop", cancellationToken).ConfigureAwait(false);
return;
}
}
@@ -184,12 +181,12 @@ private async Task UpdateDatabaseInBackgroundWorkerAsync(CancellationT
if (_service._ioService.Exists(databaseFileInfo))
{
- await _service.LogInfoAsync("Local database file exists. Patching local database").ConfigureAwait(false);
+ await _service.LogInfoAsync("Local database file exists. Patching local database", cancellationToken).ConfigureAwait(false);
return await PatchLocalDatabaseAsync(databaseFileInfo, cancellationToken).ConfigureAwait(false);
}
else
{
- await _service.LogInfoAsync("Local database file does not exist. Downloading full database").ConfigureAwait(false);
+ await _service.LogInfoAsync("Local database file does not exist. Downloading full database", cancellationToken).ConfigureAwait(false);
return await DownloadFullDatabaseAsync(databaseFileInfo, cancellationToken).ConfigureAwait(false);
}
}
@@ -207,23 +204,23 @@ private async Task UpdateDatabaseInBackgroundWorkerAsync(CancellationT
// It's the standard way to indicate that we've been asked to shut
// down.
var delay = _service._delayService.ExpectedFailureDelay;
- await _service.LogExceptionAsync(e, $"Error occurred updating. Retrying update in {delay}").ConfigureAwait(false);
+ await _service.LogExceptionAsync(e, $"Error occurred updating. Retrying update in {delay}", cancellationToken).ConfigureAwait(false);
return delay;
}
}
private async Task CleanCacheDirectoryAsync(CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Cleaning cache directory").ConfigureAwait(false);
+ await _service.LogInfoAsync("Cleaning cache directory", cancellationToken).ConfigureAwait(false);
// (intentionally not wrapped in IOUtilities. If this throws we want to restart).
if (!_service._ioService.Exists(_cacheDirectoryInfo))
{
- await _service.LogInfoAsync("Creating cache directory").ConfigureAwait(false);
+ await _service.LogInfoAsync("Creating cache directory", cancellationToken).ConfigureAwait(false);
// (intentionally not wrapped in IOUtilities. If this throws we want to restart).
_service._ioService.Create(_cacheDirectoryInfo);
- await _service.LogInfoAsync("Cache directory created").ConfigureAwait(false);
+ await _service.LogInfoAsync("Cache directory created", cancellationToken).ConfigureAwait(false);
}
cancellationToken.ThrowIfCancellationRequested();
@@ -239,22 +236,22 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo
{
var serverPath = Invariant($"Elfie_V{AddReferenceDatabaseTextFileFormatVersion}/Latest.xml");
- await _service.LogInfoAsync($"Downloading and processing full database: {serverPath}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Downloading and processing full database: {serverPath}", cancellationToken).ConfigureAwait(false);
var element = await DownloadFileAsync(serverPath, cancellationToken).ConfigureAwait(false);
var result = await ProcessFullDatabaseXElementAsync(databaseFileInfo, element, cancellationToken).ConfigureAwait(false);
- await _service.LogInfoAsync("Downloading and processing full database completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Downloading and processing full database completed", cancellationToken).ConfigureAwait(false);
return result;
}
private async Task<(bool succeeded, TimeSpan delay)> ProcessFullDatabaseXElementAsync(
FileInfo databaseFileInfo, XElement element, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Processing full database element").ConfigureAwait(false);
+ await _service.LogInfoAsync("Processing full database element", cancellationToken).ConfigureAwait(false);
// Convert the database contents in the XML to a byte[].
- var (succeeded, contentBytes) = await TryParseDatabaseElementAsync(element).ConfigureAwait(false);
+ var (succeeded, contentBytes) = await TryParseDatabaseElementAsync(element, cancellationToken).ConfigureAwait(false);
if (!succeeded)
{
@@ -264,7 +261,7 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo
// we can retrieve good data the next time around.
var failureDelay = _service._delayService.CatastrophicFailureDelay;
- await _service.LogInfoAsync($"Unable to parse full database element. Update again in {failureDelay}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Unable to parse full database element. Update again in {failureDelay}", cancellationToken).ConfigureAwait(false);
return (succeeded: false, failureDelay);
}
@@ -274,7 +271,7 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo
// searching.
try
{
- await CreateAndSetInMemoryDatabaseAsync(bytes).ConfigureAwait(false);
+ await CreateAndSetInMemoryDatabaseAsync(bytes, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (_service._reportAndSwallowException(e))
{
@@ -283,7 +280,7 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo
// isn't going to help. We need to wait until there is good data
// on the server for us to download.
var failureDelay = _service._delayService.CatastrophicFailureDelay;
- await _service.LogInfoAsync($"Unable to create database from full database element. Update again in {failureDelay}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Unable to create database from full database element. Update again in {failureDelay}", cancellationToken).ConfigureAwait(false);
return (succeeded: false, failureDelay);
}
@@ -293,13 +290,13 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo
await WriteDatabaseFileAsync(databaseFileInfo, bytes, cancellationToken).ConfigureAwait(false);
var delay = _service._delayService.UpdateSucceededDelay;
- await _service.LogInfoAsync($"Processing full database element completed. Update again in {delay}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Processing full database element completed. Update again in {delay}", cancellationToken).ConfigureAwait(false);
return (succeeded: true, delay);
}
private async Task WriteDatabaseFileAsync(FileInfo databaseFileInfo, byte[] bytes, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Writing database file").ConfigureAwait(false);
+ await _service.LogInfoAsync("Writing database file", cancellationToken).ConfigureAwait(false);
await RepeatIOAsync(
async () =>
@@ -307,7 +304,7 @@ await RepeatIOAsync(
var guidString = Guid.NewGuid().ToString();
var tempFilePath = Path.Combine(_cacheDirectoryInfo.FullName, guidString + ".tmp");
- await _service.LogInfoAsync($"Temp file path: {tempFilePath}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Temp file path: {tempFilePath}", cancellationToken).ConfigureAwait(false);
try
{
@@ -316,25 +313,25 @@ await RepeatIOAsync(
// file has been completely written to disk (at least as well as the OS can guarantee
// things).
- await _service.LogInfoAsync("Writing temp file").ConfigureAwait(false);
+ await _service.LogInfoAsync("Writing temp file", cancellationToken).ConfigureAwait(false);
// (intentionally not wrapped in IOUtilities. If this throws we want to retry writing).
_service._ioService.WriteAndFlushAllBytes(tempFilePath, bytes);
- await _service.LogInfoAsync("Writing temp file completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Writing temp file completed", cancellationToken).ConfigureAwait(false);
// If we have an existing db file, try to replace it file with the temp file.
// Otherwise, just move the temp file into place.
if (_service._ioService.Exists(databaseFileInfo))
{
- await _service.LogInfoAsync("Replacing database file").ConfigureAwait(false);
+ await _service.LogInfoAsync("Replacing database file", cancellationToken).ConfigureAwait(false);
_service._ioService.Replace(tempFilePath, databaseFileInfo.FullName, destinationBackupFileName: null, ignoreMetadataErrors: true);
- await _service.LogInfoAsync("Replace database file completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Replace database file completed", cancellationToken).ConfigureAwait(false);
}
else
{
- await _service.LogInfoAsync("Moving database file").ConfigureAwait(false);
+ await _service.LogInfoAsync("Moving database file", cancellationToken).ConfigureAwait(false);
_service._ioService.Move(tempFilePath, databaseFileInfo.FullName);
- await _service.LogInfoAsync("Moving database file completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Moving database file completed", cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -345,17 +342,17 @@ await RepeatIOAsync(
}
}, cancellationToken).ConfigureAwait(false);
- await _service.LogInfoAsync("Writing database file completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Writing database file completed", cancellationToken).ConfigureAwait(false);
}
private async Task PatchLocalDatabaseAsync(FileInfo databaseFileInfo, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Patching local database").ConfigureAwait(false);
+ await _service.LogInfoAsync("Patching local database", cancellationToken).ConfigureAwait(false);
- await _service.LogInfoAsync("Reading in local database").ConfigureAwait(false);
+ await _service.LogInfoAsync("Reading in local database", cancellationToken).ConfigureAwait(false);
// (intentionally not wrapped in IOUtilities. If this throws we want to restart).
var databaseBytes = _service._ioService.ReadAllBytes(databaseFileInfo.FullName);
- await _service.LogInfoAsync($"Reading in local database completed. databaseBytes.Length={databaseBytes.Length}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Reading in local database completed. databaseBytes.Length={databaseBytes.Length}", cancellationToken).ConfigureAwait(false);
// Make a database instance out of those bytes and set is as the current in memory database
// that searches will run against. If we can't make a database instance from these bytes
@@ -364,24 +361,24 @@ private async Task PatchLocalDatabaseAsync(FileInfo databaseFileInfo,
AddReferenceDatabase database;
try
{
- database = await CreateAndSetInMemoryDatabaseAsync(databaseBytes).ConfigureAwait(false);
+ database = await CreateAndSetInMemoryDatabaseAsync(databaseBytes, cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (_service._reportAndSwallowException(e))
{
- await _service.LogExceptionAsync(e, "Error creating database from local copy. Downloading full database").ConfigureAwait(false);
+ await _service.LogExceptionAsync(e, "Error creating database from local copy. Downloading full database", cancellationToken).ConfigureAwait(false);
return await DownloadFullDatabaseAsync(databaseFileInfo, cancellationToken).ConfigureAwait(false);
}
// Now attempt to download and apply patch file.
var serverPath = Invariant($"Elfie_V{AddReferenceDatabaseTextFileFormatVersion}/{database.DatabaseVersion}_Patch.xml");
- await _service.LogInfoAsync("Downloading and processing patch file: " + serverPath).ConfigureAwait(false);
+ await _service.LogInfoAsync("Downloading and processing patch file: " + serverPath, cancellationToken).ConfigureAwait(false);
var element = await DownloadFileAsync(serverPath, cancellationToken).ConfigureAwait(false);
var delayUntilUpdate = await ProcessPatchXElementAsync(databaseFileInfo, element, databaseBytes, cancellationToken).ConfigureAwait(false);
- await _service.LogInfoAsync("Downloading and processing patch file completed").ConfigureAwait(false);
- await _service.LogInfoAsync("Patching local database completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Downloading and processing patch file completed", cancellationToken).ConfigureAwait(false);
+ await _service.LogInfoAsync("Patching local database completed", cancellationToken).ConfigureAwait(false);
return delayUntilUpdate;
}
@@ -392,9 +389,9 @@ private async Task PatchLocalDatabaseAsync(FileInfo databaseFileInfo,
/// indicates that our data is corrupt), the exception will bubble up and must be appropriately
/// dealt with by the caller.
///
- private async Task CreateAndSetInMemoryDatabaseAsync(byte[] bytes)
+ private async Task CreateAndSetInMemoryDatabaseAsync(byte[] bytes, CancellationToken cancellationToken)
{
- var database = await CreateDatabaseFromBytesAsync(bytes).ConfigureAwait(false);
+ var database = await CreateDatabaseFromBytesAsync(bytes, cancellationToken).ConfigureAwait(false);
_service._sourceToDatabase[_source] = new AddReferenceDatabaseWrapper(database);
return database;
}
@@ -404,11 +401,11 @@ private async Task ProcessPatchXElementAsync(
{
try
{
- await _service.LogInfoAsync("Processing patch element").ConfigureAwait(false);
+ await _service.LogInfoAsync("Processing patch element", cancellationToken).ConfigureAwait(false);
var delayUntilUpdate = await TryProcessPatchXElementAsync(databaseFileInfo, patchElement, databaseBytes, cancellationToken).ConfigureAwait(false);
if (delayUntilUpdate != null)
{
- await _service.LogInfoAsync($"Processing patch element completed. Update again in {delayUntilUpdate.Value}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Processing patch element completed. Update again in {delayUntilUpdate.Value}", cancellationToken).ConfigureAwait(false);
return delayUntilUpdate.Value;
}
@@ -416,7 +413,7 @@ private async Task ProcessPatchXElementAsync(
}
catch (Exception e) when (_service._reportAndSwallowException(e))
{
- await _service.LogExceptionAsync(e, "Error occurred while processing patch element. Downloading full database").ConfigureAwait(false);
+ await _service.LogExceptionAsync(e, "Error occurred while processing patch element. Downloading full database", cancellationToken).ConfigureAwait(false);
// Fall through and download full database.
}
@@ -430,25 +427,25 @@ private async Task ProcessPatchXElementAsync(
if (upToDate)
{
- await _service.LogInfoAsync("Local version is up to date").ConfigureAwait(false);
+ await _service.LogInfoAsync("Local version is up to date", cancellationToken).ConfigureAwait(false);
return _service._delayService.UpdateSucceededDelay;
}
if (tooOld)
{
- await _service.LogInfoAsync("Local version too old").ConfigureAwait(false);
+ await _service.LogInfoAsync("Local version too old", cancellationToken).ConfigureAwait(false);
return null;
}
- await _service.LogInfoAsync($"Got patch. databaseBytes.Length={databaseBytes.Length} patchBytes.Length={patchBytes.Length}.").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Got patch. databaseBytes.Length={databaseBytes.Length} patchBytes.Length={patchBytes.Length}.", cancellationToken).ConfigureAwait(false);
// We have patch data. Apply it to our current database bytes to produce the new
// database.
- await _service.LogInfoAsync("Applying patch").ConfigureAwait(false);
+ await _service.LogInfoAsync("Applying patch", cancellationToken).ConfigureAwait(false);
var finalBytes = _service._patchService.ApplyPatch(databaseBytes, patchBytes);
- await _service.LogInfoAsync($"Applying patch completed. finalBytes.Length={finalBytes.Length}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Applying patch completed. finalBytes.Length={finalBytes.Length}", cancellationToken).ConfigureAwait(false);
- await CreateAndSetInMemoryDatabaseAsync(finalBytes).ConfigureAwait(false);
+ await CreateAndSetInMemoryDatabaseAsync(finalBytes, cancellationToken).ConfigureAwait(false);
await WriteDatabaseFileAsync(databaseFileInfo, finalBytes, cancellationToken).ConfigureAwait(false);
@@ -483,17 +480,17 @@ private static void ParsePatchElement(XElement patchElement, out bool upToDate,
}
}
- private async Task CreateDatabaseFromBytesAsync(byte[] bytes)
+ private async Task CreateDatabaseFromBytesAsync(byte[] bytes, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Creating database from bytes").ConfigureAwait(false);
+ await _service.LogInfoAsync("Creating database from bytes", cancellationToken).ConfigureAwait(false);
var result = _service._databaseFactoryService.CreateDatabaseFromBytes(bytes);
- await _service.LogInfoAsync("Creating database from bytes completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Creating database from bytes completed", cancellationToken).ConfigureAwait(false);
return result;
}
private async Task DownloadFileAsync(string serverPath, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Creating download client: " + serverPath).ConfigureAwait(false);
+ await _service.LogInfoAsync("Creating download client: " + serverPath, cancellationToken).ConfigureAwait(false);
// Create a client that will attempt to download the specified file. The client works
// in the following manner:
@@ -509,18 +506,18 @@ private async Task DownloadFileAsync(string serverPath, CancellationTo
var pollingMinutes = (int)TimeSpan.FromDays(1).TotalMinutes;
using var client = _service._remoteControlService.CreateClient(HostId, serverPath, pollingMinutes);
- await _service.LogInfoAsync("Creating download client completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Creating download client completed", cancellationToken).ConfigureAwait(false);
// Poll the client every minute until we get the file.
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
- var resultOpt = await TryDownloadFileAsync(client).ConfigureAwait(false);
+ var resultOpt = await TryDownloadFileAsync(client, cancellationToken).ConfigureAwait(false);
if (resultOpt == null)
{
var delay = _service._delayService.CachePollDelay;
- await _service.LogInfoAsync($"File not downloaded. Trying again in {delay}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"File not downloaded. Trying again in {delay}", cancellationToken).ConfigureAwait(false);
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
else
@@ -532,9 +529,9 @@ private async Task DownloadFileAsync(string serverPath, CancellationTo
}
/// Returns 'null' if download is not available and caller should keep polling.
- private async Task TryDownloadFileAsync(IRemoteControlClient client)
+ private async Task TryDownloadFileAsync(IRemoteControlClient client, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Read file from client").ConfigureAwait(false);
+ await _service.LogInfoAsync("Read file from client", cancellationToken).ConfigureAwait(false);
// "ReturnsNull": Only return a file if we have it locally *and* it's not older than our polling time (1 day).
@@ -542,12 +539,12 @@ private async Task TryDownloadFileAsync(IRemoteControlClient client)
if (stream == null)
{
- await _service.LogInfoAsync("Read file completed. Client returned no data").ConfigureAwait(false);
+ await _service.LogInfoAsync("Read file completed. Client returned no data", cancellationToken).ConfigureAwait(false);
return null;
}
- await _service.LogInfoAsync("Read file completed. Client returned data").ConfigureAwait(false);
- await _service.LogInfoAsync("Converting data to XElement").ConfigureAwait(false);
+ await _service.LogInfoAsync("Read file completed. Client returned data", cancellationToken).ConfigureAwait(false);
+ await _service.LogInfoAsync("Converting data to XElement", cancellationToken).ConfigureAwait(false);
// We're reading in our own XML file, but even so, use conservative settings
// just to be on the safe side. First, disallow DTDs entirely (we will never
@@ -562,7 +559,7 @@ private async Task TryDownloadFileAsync(IRemoteControlClient client)
using var reader = XmlReader.Create(stream, settings);
var result = XElement.Load(reader);
- await _service.LogInfoAsync("Converting data to XElement completed").ConfigureAwait(false);
+ await _service.LogInfoAsync("Converting data to XElement completed", cancellationToken).ConfigureAwait(false);
return result;
}
@@ -588,15 +585,15 @@ private async Task RepeatIOAsync(Func action, CancellationToken cancellati
// around the reporting in this case.
var delay = _service._delayService.FileWriteDelay;
- await _service.LogExceptionAsync(e, $"Operation failed. Trying again after {delay}").ConfigureAwait(false);
+ await _service.LogExceptionAsync(e, $"Operation failed. Trying again after {delay}", cancellationToken).ConfigureAwait(false);
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
}
}
}
- private async Task<(bool succeeded, byte[] contentBytes)> TryParseDatabaseElementAsync(XElement element)
+ private async Task<(bool succeeded, byte[] contentBytes)> TryParseDatabaseElementAsync(XElement element, CancellationToken cancellationToken)
{
- await _service.LogInfoAsync("Parsing database element").ConfigureAwait(false);
+ await _service.LogInfoAsync("Parsing database element", cancellationToken).ConfigureAwait(false);
var contentsAttribute = element.Attribute(ContentAttributeName);
if (contentsAttribute == null)
{
@@ -605,7 +602,7 @@ private async Task RepeatIOAsync(Func action, CancellationToken cancellati
return (succeeded: false, (byte[])null);
}
- var contentBytes = await ConvertContentAttributeAsync(contentsAttribute).ConfigureAwait(false);
+ var contentBytes = await ConvertContentAttributeAsync(contentsAttribute, cancellationToken).ConfigureAwait(false);
var checksumAttribute = element.Attribute(ChecksumAttributeName);
if (checksumAttribute != null)
@@ -628,7 +625,7 @@ private async Task RepeatIOAsync(Func action, CancellationToken cancellati
return (succeeded: true, contentBytes);
}
- private async Task ConvertContentAttributeAsync(XAttribute contentsAttribute)
+ private async Task ConvertContentAttributeAsync(XAttribute contentsAttribute, CancellationToken cancellationToken)
{
var text = contentsAttribute.Value;
var compressedBytes = Convert.FromBase64String(text);
@@ -643,7 +640,7 @@ private async Task ConvertContentAttributeAsync(XAttribute contentsAttri
var bytes = outStream.ToArray();
- await _service.LogInfoAsync($"Parsing complete. bytes.length={bytes.Length}").ConfigureAwait(false);
+ await _service.LogInfoAsync($"Parsing complete. bytes.length={bytes.Length}", cancellationToken).ConfigureAwait(false);
return bytes;
}
}
diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs
index 1cb312506eacd..077bf39342f07 100644
--- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs
+++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs
@@ -66,20 +66,20 @@ internal SymbolSearchUpdateEngine(
_reportAndSwallowException = reportAndSwallowException;
}
- public Task> FindPackagesWithTypeAsync(
+ public ValueTask> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken)
{
if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper))
{
// Don't have a database to search.
- return SpecializedTasks.EmptyImmutableArray();
+ return new(ImmutableArray.Empty);
}
var database = databaseWrapper.Database;
if (name == "var")
{
// never find anything named 'var'.
- return SpecializedTasks.EmptyImmutableArray();
+ return new(ImmutableArray.Empty);
}
var query = new MemberQuery(name, isFullSuffix: true, isFullNamespace: false);
@@ -102,16 +102,16 @@ public Task> FindPackagesWithTypeAsync(
}
}
- return Task.FromResult(result.ToImmutableAndFree());
+ return new(result.ToImmutableAndFree());
}
- public Task> FindPackagesWithAssemblyAsync(
+ public ValueTask> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken)
{
if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper))
{
// Don't have a database to search.
- return SpecializedTasks.EmptyImmutableArray();
+ return new(ImmutableArray.Empty);
}
var result = ArrayBuilder.GetInstance();
@@ -132,33 +132,35 @@ public Task> FindPackagesWithAssemblyA
// Ignore any reference assembly results.
if (symbol.PackageName.ToString() != MicrosoftAssemblyReferencesName)
{
+ var version = database.GetPackageVersion(symbol.Index).ToString();
+
result.Add(new PackageWithAssemblyResult(
symbol.PackageName.ToString(),
- database.GetPackageVersion(symbol.Index).ToString(),
- GetRank(symbol)));
+ GetRank(symbol),
+ string.IsNullOrWhiteSpace(version) ? null : version));
}
}
}
}
- return Task.FromResult(result.ToImmutableAndFree());
+ return new(result.ToImmutableAndFree());
}
- public Task> FindReferenceAssembliesWithTypeAsync(
+ public ValueTask> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken)
{
// Our reference assembly data is stored in the nuget.org DB.
if (!_sourceToDatabase.TryGetValue(NugetOrgSource, out var databaseWrapper))
{
// Don't have a database to search.
- return SpecializedTasks.EmptyImmutableArray();
+ return new(ImmutableArray.Empty);
}
var database = databaseWrapper.Database;
if (name == "var")
{
// never find anything named 'var'.
- return SpecializedTasks.EmptyImmutableArray();
+ return new(ImmutableArray.Empty);
}
var query = new MemberQuery(name, isFullSuffix: true, isFullNamespace: false);
@@ -186,7 +188,7 @@ public Task> FindReferenceAssemb
}
}
- return Task.FromResult(results.ToImmutableAndFree());
+ return new(results.ToImmutableAndFree());
}
private static List FilterToViableTypes(PartialArray symbols)
@@ -211,9 +213,9 @@ private PackageWithTypeResult CreateResult(AddReferenceDatabase database, Symbol
return new PackageWithTypeResult(
packageName: packageName,
- typeName: type.Name.ToString(),
- version: version,
rank: GetRank(type),
+ typeName: type.Name.ToString(),
+ version: string.IsNullOrWhiteSpace(version) ? null : version,
containingNamespaceNames: nameParts.ToImmutableAndFree());
}
diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs
index 1224ad7545023..dbf4d896394ec 100644
--- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs
+++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs
@@ -4,13 +4,11 @@
#nullable enable
-using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.SymbolSearch
{
@@ -32,9 +30,8 @@ public static async Task CreateEngineAsync(
var client = await RemoteHostClient.TryGetClientAsync(workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var callbackObject = new CallbackObject(logService);
- var session = await client.CreateConnectionAsync(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, callbackObject, cancellationToken).ConfigureAwait(false);
- return new RemoteUpdateEngine(workspace, session);
+ var connection = await client.CreateConnectionAsync(logService, cancellationToken).ConfigureAwait(false);
+ return new RemoteUpdateEngine(connection);
}
// Couldn't go out of proc. Just do everything inside the current process.
@@ -53,97 +50,64 @@ public static ISymbolSearchUpdateEngine CreateEngineInProcess(ISymbolSearchLogSe
private sealed class NoOpUpdateEngine : ISymbolSearchUpdateEngine
{
- public Task> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken)
- => SpecializedTasks.EmptyImmutableArray();
+ public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
- public Task> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken)
- => SpecializedTasks.EmptyImmutableArray();
+ public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
- public Task> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken)
- => SpecializedTasks.EmptyImmutableArray();
+ public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
- public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory)
- => Task.CompletedTask;
+ public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken)
+ => default;
}
private sealed class RemoteUpdateEngine : ISymbolSearchUpdateEngine
{
- private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1);
+ private readonly RemoteServiceConnection _connection;
- private readonly Workspace _workspace;
- private readonly RemoteServiceConnection _session;
-
- public RemoteUpdateEngine(
- Workspace workspace,
- RemoteServiceConnection session)
- {
- _workspace = workspace;
- _session = session;
- }
+ public RemoteUpdateEngine(RemoteServiceConnection connection)
+ => _connection = connection;
public void Dispose()
- {
- _session.Dispose();
- }
+ => _connection.Dispose();
- public async Task> FindPackagesWithTypeAsync(
- string source, string name, int arity, CancellationToken cancellationToken)
+ public async ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken)
{
- var results = await _session.RunRemoteAsync>(
- nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithTypeAsync),
- solution: null,
- new object[] { source, name, arity },
+ var result = await _connection.TryInvokeAsync>(
+ (service, cancellationToken) => service.FindPackagesWithTypeAsync(source, name, arity, cancellationToken),
cancellationToken).ConfigureAwait(false);
- return results.ToImmutableArray();
+ return result.HasValue ? result.Value : ImmutableArray.Empty;
}
- public async Task> FindPackagesWithAssemblyAsync(
+ public async ValueTask> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken)
{
- var results = await _session.RunRemoteAsync>(
- nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithAssemblyAsync),
- solution: null,
- new object[] { source, assemblyName },
+ var result = await _connection.TryInvokeAsync>(
+ (service, cancellationToken) => service.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken),
cancellationToken).ConfigureAwait(false);
- return results.ToImmutableArray();
+ return result.HasValue ? result.Value : ImmutableArray.Empty;
}
- public async Task> FindReferenceAssembliesWithTypeAsync(
+ public async ValueTask> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken)
{
- var results = await _session.RunRemoteAsync>(
- nameof(IRemoteSymbolSearchUpdateEngine.FindReferenceAssembliesWithTypeAsync),
- solution: null,
- new object[] { name, arity },
+ var result = await _connection.TryInvokeAsync>(
+ (service, cancellationToken) => service.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken),
cancellationToken).ConfigureAwait(false);
- return results.ToImmutableArray();
+ return result.HasValue ? result.Value : ImmutableArray.Empty;
}
- public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory)
- => _session.RunRemoteAsync(
- nameof(IRemoteSymbolSearchUpdateEngine.UpdateContinuouslyAsync),
- solution: null,
- new object[] { sourceName, localSettingsDirectory },
- CancellationToken.None);
- }
-
- private class CallbackObject : ISymbolSearchLogService
- {
- private readonly ISymbolSearchLogService _logService;
-
- public CallbackObject(ISymbolSearchLogService logService)
+ public async ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken)
{
- _logService = logService;
+ _ = await _connection.TryInvokeAsync(
+ (service, cancellationToken) => service.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken),
+ cancellationToken).ConfigureAwait(false);
}
-
- public Task LogExceptionAsync(string exception, string text)
- => _logService.LogExceptionAsync(exception, text);
-
- public Task LogInfoAsync(string text)
- => _logService.LogInfoAsync(text);
}
}
}
diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
index d9ea28b05df5a..572b99a7ec0e0 100644
--- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
+++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs
@@ -129,30 +129,50 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions()
}
[Fact]
- public async Task TestGetCodeFixWithExceptionInRegisterMethod()
+ public async Task TestGetCodeFixWithExceptionInRegisterMethod_Diagnostic()
+ {
+ await GetFirstDiagnosticWithFixWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethod());
+ }
+
+ [Fact]
+ public async Task TestGetCodeFixWithExceptionInRegisterMethod_Fixes()
{
- await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInRegisterMethod());
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethod());
}
[Fact]
- public async Task TestGetCodeFixWithExceptionInRegisterMethodAsync()
+ public async Task TestGetCodeFixWithExceptionInRegisterMethodAsync_Diagnostic()
+ {
+ await GetFirstDiagnosticWithFixWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
+ }
+
+ [Fact]
+ public async Task TestGetCodeFixWithExceptionInRegisterMethodAsync_Fixes()
{
- await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInRegisterMethodAsync());
}
[Fact]
- public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds()
+ public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds_Diagnostic()
+ {
+ await GetFirstDiagnosticWithFixWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
+ }
+
+ [Fact]
+ public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds_Fixes()
{
- await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds());
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21533")]
- public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds2()
+ public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds_Diagnostic2()
+ {
+ await GetFirstDiagnosticWithFixWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
+ }
+
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/21533")]
+ public async Task TestGetCodeFixWithExceptionInFixableDiagnosticIds_Fixes2()
{
- await GetFirstDiagnosticWithFixAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
await GetAddedFixesWithExceptionValidationAsync(new ErrorCases.ExceptionInFixableDiagnosticIds2());
}
@@ -176,6 +196,11 @@ private static async Task> GetAddedFixesAsync(
using var workspace = tuple.workspace;
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager);
var incrementalAnalyzer = (IIncrementalAnalyzerProvider)tuple.analyzerService;
var analyzer = incrementalAnalyzer.CreateIncrementalAnalyzer(workspace);
@@ -190,17 +215,26 @@ private static async Task> GetAddedFixesAsync(
Assert.False(extensionManager.IsIgnored(codefix));
}
+ Assert.Equal(exception || throwExceptionInFixerCreation, errorReported);
+
return fixes;
}
- private static async Task GetFirstDiagnosticWithFixAsync(CodeFixProvider codefix)
+ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync(CodeFixProvider codefix)
{
var tuple = ServiceSetup(codefix);
using var workspace = tuple.workspace;
+
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager);
var unused = await tuple.codeFixService.GetMostSevereFixableDiagnosticAsync(document, TextSpan.FromBounds(0, 0), cancellationToken: CancellationToken.None);
Assert.True(extensionManager.IsDisabled(codefix));
Assert.False(extensionManager.IsIgnored(codefix));
+ Assert.True(errorReported);
}
private static (TestWorkspace workspace, DiagnosticAnalyzerService analyzerService, CodeFixService codeFixService, IErrorLoggerService errorLogger) ServiceSetup(
diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs
index 75741bd1b3542..80423f046fbbc 100644
--- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs
+++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs
@@ -50,7 +50,14 @@ public async Task TestProjectRefactoringAsync()
private static async Task VerifyRefactoringDisabledAsync()
where T : CodeRefactoringProvider
{
- using var workspace = TestWorkspace.CreateCSharp(@"class Program {}", composition: EditorTestCompositions.EditorFeatures.AddParts(typeof(T)));
+ using var workspace = TestWorkspace.CreateCSharp(@"class Program {}",
+ composition: EditorTestCompositions.EditorFeatures.AddParts(typeof(T)));
+
+ var errorReportingService = (TestErrorReportingService)workspace.Services.GetRequiredService();
+
+ var errorReported = false;
+ errorReportingService.OnError = message => errorReported = true;
+
var refactoringService = workspace.GetService();
var codeRefactoring = workspace.ExportProvider.GetExportedValues().OfType().Single();
@@ -60,6 +67,8 @@ private static async Task VerifyRefactoringDisabledAsync()
var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CancellationToken.None);
Assert.True(extensionManager.IsDisabled(codeRefactoring));
Assert.False(extensionManager.IsIgnored(codeRefactoring));
+
+ Assert.True(errorReported);
}
internal class StubRefactoring : CodeRefactoringProvider
diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
index 06e6fcc240250..b8d11886594af 100644
--- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
+++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs
@@ -978,8 +978,8 @@ void M()
// Then invoke analysis without cancellation token, and verify non-cancelled diagnostic.
var diagnosticsMap = await diagnosticComputer.GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics: false,
logPerformanceInfo: false, getTelemetryInfo: false, cancellationToken: CancellationToken.None);
- var builder = diagnosticsMap.AnalysisResult.Values.Single();
- var diagnostic = kind == AnalysisKind.Syntax ? builder.SyntaxLocals.Values.Single().Single() : builder.SemanticLocals.Values.Single().Single();
+ var builder = diagnosticsMap.Diagnostics.Single().diagnosticMap;
+ var diagnostic = kind == AnalysisKind.Syntax ? builder.Syntax.Single().Item2.Single() : builder.Semantic.Single().Item2.Single();
Assert.Equal(CancellationTestAnalyzer.NonCanceledDiagnosticId, diagnostic.Id);
}
diff --git a/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs b/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs
index 0ffeb83a92b89..900a7f886f901 100644
--- a/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs
+++ b/src/EditorFeatures/Test/FindReferences/FindReferencesCommandHandlerTests.cs
@@ -28,14 +28,14 @@ private class MockFindUsagesContext : FindUsagesContext
{
public readonly List Result = new List();
- public override Task OnDefinitionFoundAsync(DefinitionItem definition)
+ public override ValueTask OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (Result)
{
Result.Add(definition);
}
- return Task.CompletedTask;
+ return default;
}
}
diff --git a/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj b/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj
index 8298048cd39a5..ca47481e9b233 100644
--- a/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj
+++ b/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj
@@ -9,8 +9,8 @@
true
-
-
+
+
diff --git a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb
index 2df3f304ac0e2..5587b2b994306 100644
--- a/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb
+++ b/src/EditorFeatures/Test2/FindReferences/FindReferencesTests.vb
@@ -229,20 +229,20 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.FindReferences
Return definition.DisplayIfNoReferences
End Function
- Public Overrides Function OnDefinitionFoundAsync(definition As DefinitionItem) As Task
+ Public Overrides Function OnDefinitionFoundAsync(definition As DefinitionItem) As ValueTask
SyncLock gate
Me.Definitions.Add(definition)
End SyncLock
- Return Task.CompletedTask
+ Return Nothing
End Function
- Public Overrides Function OnReferenceFoundAsync(reference As SourceReferenceItem) As Task
+ Public Overrides Function OnReferenceFoundAsync(reference As SourceReferenceItem) As ValueTask
SyncLock gate
References.Add(reference)
End SyncLock
- Return Task.CompletedTask
+ Return Nothing
End Function
End Class
diff --git a/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb b/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb
index 5bca6ac79ba74..8ae5343fc9e51 100644
--- a/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb
+++ b/src/EditorFeatures/Test2/ReferenceHighlighting/DocumentHighlightsServiceTests.vb
@@ -4,16 +4,16 @@
Imports System.Collections.Immutable
Imports System.Threading
-Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
+Imports Microsoft.CodeAnalysis.Remote.Testing
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.ReferenceHighlighting
- <[UseExportProvider]>
+
Public Class DocumentHighlightsServiceTests
-
- Public Async Function TestMultipleLanguagesPassedToAPI() As Task
+
+ Public Async Function TestMultipleLanguagesPassedToAPI(testHost As TestHost) As Task
Dim workspaceElement =
@@ -34,16 +34,20 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.ReferenceHighlighting
- Using workspace = TestWorkspace.Create(workspaceElement)
+ Using workspace = TestWorkspace.Create(workspaceElement, composition:=EditorTestCompositions.EditorFeatures.WithTestHostParts(testHost))
Dim position = workspace.DocumentWithCursor.CursorPosition.Value
Dim solution = workspace.CurrentSolution
Dim csharpDocument = solution.Projects.Single(Function(p) p.Language = LanguageNames.CSharp).Documents.Single()
Dim vbDocument = solution.Projects.Single(Function(p) p.Language = LanguageNames.VisualBasic).Documents.Single()
- Dim service = csharpDocument.GetLanguageService(Of Microsoft.CodeAnalysis.DocumentHighlighting.IDocumentHighlightsService)
- Await service.GetDocumentHighlightsAsync(
+ Dim service = csharpDocument.GetLanguageService(Of DocumentHighlighting.IDocumentHighlightsService)
+ Dim highlights = Await service.GetDocumentHighlightsAsync(
csharpDocument, position, ImmutableHashSet.Create(csharpDocument, vbDocument), CancellationToken.None)
+
+ AssertEx.Equal(
+ {"Test1.cs: Reference [102..108)"},
+ highlights.Select(Function(h) $"{h.Document.Name}: {String.Join(",", h.HighlightSpans.Select(Function(span) $"{span.Kind} {span.TextSpan}"))}"))
End Using
End Function
End Class
diff --git a/src/EditorFeatures/TestUtilities/CodeLens/AbstractCodeLensTest.cs b/src/EditorFeatures/TestUtilities/CodeLens/AbstractCodeLensTest.cs
index 6109f4dd130ba..ee3f833955d8e 100644
--- a/src/EditorFeatures/TestUtilities/CodeLens/AbstractCodeLensTest.cs
+++ b/src/EditorFeatures/TestUtilities/CodeLens/AbstractCodeLensTest.cs
@@ -35,8 +35,8 @@ protected static async Task RunCountTest(XElement input, int cap = 0)
var result = await new CodeLensReferencesService().GetReferenceCountAsync(workspace.CurrentSolution, annotatedDocument.Id,
declarationSyntaxNode, cap, CancellationToken.None);
Assert.NotNull(result);
- Assert.Equal(expected, result.Count);
- Assert.Equal(isCapped, result.IsCapped);
+ Assert.Equal(expected, result.Value.Count);
+ Assert.Equal(isCapped, result.Value.IsCapped);
}
}
}
@@ -63,8 +63,8 @@ protected static async Task RunReferenceTest(XElement input)
var declarationSyntaxNode = syntaxNode.FindNode(span);
var result = await new CodeLensReferencesService().FindReferenceLocationsAsync(workspace.CurrentSolution,
annotatedDocument.Id, declarationSyntaxNode, CancellationToken.None);
- var count = result.Count();
- Assert.Equal(expected, count);
+ Assert.True(result.HasValue);
+ Assert.Equal(expected, result.Value.Length);
}
}
}
@@ -91,8 +91,8 @@ protected static async Task RunMethodReferenceTest(XElement input)
var declarationSyntaxNode = syntaxNode.FindNode(span);
var result = await new CodeLensReferencesService().FindReferenceMethodsAsync(workspace.CurrentSolution,
annotatedDocument.Id, declarationSyntaxNode, CancellationToken.None);
- var count = result.Count();
- Assert.Equal(expected, count);
+ Assert.True(result.HasValue);
+ Assert.Equal(expected, result.Value.Length);
}
}
}
diff --git a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb
index 73fd13b6d4a32..bd1bfaf985bae 100644
--- a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb
+++ b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesLSPService.vb
@@ -14,8 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.FindUsages
- Public Sub New(threadingContext As IThreadingContext)
- MyBase.New(threadingContext)
+ Public Sub New()
End Sub
End Class
End Namespace
diff --git a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb
index e37ca58cde30e..c2e7413f2a293 100644
--- a/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb
+++ b/src/EditorFeatures/VisualBasic/FindUsages/VisualBasicFindUsagesService.vb
@@ -14,8 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.FindUsages
- Public Sub New(threadingContext As IThreadingContext)
- MyBase.New(threadingContext)
+ Public Sub New()
End Sub
End Class
End Namespace
diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb
index 348e34cb163f5..6adcea71f3438 100644
--- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb
+++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb
@@ -57,7 +57,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
@@ -86,7 +86,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
@@ -115,7 +115,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
@@ -140,7 +140,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
@@ -165,7 +165,7 @@ New TestParameters(fixProviderData:=New ProviderData(installerServiceMock.Object
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2")))
@@ -207,7 +207,7 @@ parameters:=New TestParameters(index:=2, fixProviderData:=data))
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
@@ -239,7 +239,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
Dim packageServiceMock = New Mock(Of ISymbolSearchService)(MockBehavior.Strict)
packageServiceMock.Setup(Function(s) s.FindReferenceAssembliesWithTypeAsync("NuGetType", 0, It.IsAny(Of CancellationToken))).
- Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult)))
+ Returns(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty))
packageServiceMock.Setup(Function(s) s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())).
Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace")))
@@ -257,17 +257,17 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
installerServiceMock.Verify()
End Function
- Private Shared Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As Task(Of IList(Of PackageWithTypeResult))
+ Private Shared Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As ValueTask(Of ImmutableArray(Of PackageWithTypeResult))
Return CreateSearchResult(New PackageWithTypeResult(
packageName:=packageName,
+ rank:=0,
typeName:=typeName,
version:=Nothing,
- rank:=0,
containingNamespaceNames:=nameParts))
End Function
- Private Shared Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As Task(Of IList(Of PackageWithTypeResult))
- Return Task.FromResult(Of IList(Of PackageWithTypeResult))(ImmutableArray.Create(results))
+ Private Shared Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As ValueTask(Of ImmutableArray(Of PackageWithTypeResult))
+ Return New ValueTask(Of ImmutableArray(Of PackageWithTypeResult))(ImmutableArray.Create(results))
End Function
Private Shared Function CreateNameParts(ParamArray parts As String()) As ImmutableArray(Of String)
diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
index 1dd0a88aa85c3..850960da63803 100644
--- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
+++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs
@@ -59,26 +59,15 @@ public async Task> GetFixesAsync(
var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var callbackTarget = new RemoteSymbolSearchService(symbolSearchService);
+ var callbackTarget = new RemoteAddImportServiceCallback(symbolSearchService);
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteAddImportFeatureService.GetFixesAsync),
+ var result = await client.TryInvokeAsync>(
document.Project.Solution,
- new object[]
- {
- document.Id,
- span,
- diagnosticId,
- maxResults,
- placeSystemNamespaceFirst,
- searchReferenceAssemblies,
- packageSources
- },
+ (service, solutionInfo, cancellationToken) => service.GetFixesAsync(solutionInfo, document.Id, span, diagnosticId, maxResults, placeSystemNamespaceFirst, searchReferenceAssemblies, packageSources, cancellationToken),
callbackTarget,
cancellationToken).ConfigureAwait(false);
- return result.ToImmutableArray();
+ return result.HasValue ? result.Value : ImmutableArray.Empty;
}
return await GetFixesInCurrentProcessAsync(
diff --git a/src/Features/Core/Portable/AddImport/AddImportFixData.cs b/src/Features/Core/Portable/AddImport/AddImportFixData.cs
index 7d7ce3086fcfb..bf74a8c8dfa2a 100644
--- a/src/Features/Core/Portable/AddImport/AddImportFixData.cs
+++ b/src/Features/Core/Portable/AddImport/AddImportFixData.cs
@@ -4,14 +4,17 @@
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.AddImport
{
- internal class AddImportFixData
+ [DataContract]
+ internal sealed class AddImportFixData
{
+ [DataMember(Order = 0)]
public AddImportFixKind Kind { get; }
///
@@ -20,29 +23,34 @@ internal class AddImportFixData
/// May be empty for fixes that don't need to add an import and only do something like
/// add a project/metadata reference.
///
- public IList TextChanges { get; }
+ [DataMember(Order = 1)]
+ public readonly ImmutableArray TextChanges;
///
/// String to display in the lightbulb menu.
///
- public string Title { get; private set; }
+ [DataMember(Order = 2)]
+ public readonly string Title;
///
/// Tags that control what glyph is displayed in the lightbulb menu.
///
- public IList Tags { get; private set; }
+ [DataMember(Order = 3)]
+ public readonly ImmutableArray Tags;
///
/// The priority this item should have in the lightbulb list.
///
- public CodeActionPriority Priority { get; private set; }
+ [DataMember(Order = 4)]
+ public readonly CodeActionPriority Priority;
#region When adding P2P references.
///
/// The optional id for a we'd like to add a reference to.
///
- public ProjectId ProjectReferenceToAdd { get; private set; }
+ [DataMember(Order = 5)]
+ public readonly ProjectId ProjectReferenceToAdd;
#endregion
@@ -53,84 +61,104 @@ internal class AddImportFixData
/// is the id for the we can find that
/// referenced from.
///
- public ProjectId PortableExecutableReferenceProjectId { get; private set; }
+ [DataMember(Order = 6)]
+ public readonly ProjectId PortableExecutableReferenceProjectId;
///
/// If we want to add a metadata reference, this
/// is the for it.
///
- public string PortableExecutableReferenceFilePathToAdd { get; private set; }
+ [DataMember(Order = 7)]
+ public readonly string PortableExecutableReferenceFilePathToAdd;
#endregion
#region When adding an assembly reference
- public string AssemblyReferenceAssemblyName { get; private set; }
- public string AssemblyReferenceFullyQualifiedTypeName { get; private set; }
+ [DataMember(Order = 8)]
+ public readonly string AssemblyReferenceAssemblyName;
+
+ [DataMember(Order = 9)]
+ public readonly string AssemblyReferenceFullyQualifiedTypeName;
#endregion
#region When adding a package reference
- public string PackageSource { get; private set; }
- public string PackageName { get; private set; }
- public string PackageVersionOpt { get; private set; }
+ [DataMember(Order = 10)]
+ public readonly string PackageSource;
+
+ [DataMember(Order = 11)]
+ public readonly string PackageName;
+
+ [DataMember(Order = 12)]
+ public readonly string PackageVersionOpt;
#endregion
- private AddImportFixData(
+ // Must be public since it's used for deserialization.
+ public AddImportFixData(
AddImportFixKind kind,
- ImmutableArray textChanges)
+ ImmutableArray textChanges,
+ string title = null,
+ ImmutableArray tags = default,
+ CodeActionPriority priority = default,
+ ProjectId projectReferenceToAdd = null,
+ ProjectId portableExecutableReferenceProjectId = null,
+ string portableExecutableReferenceFilePathToAdd = null,
+ string assemblyReferenceAssemblyName = null,
+ string assemblyReferenceFullyQualifiedTypeName = null,
+ string packageSource = null,
+ string packageName = null,
+ string packageVersionOpt = null)
{
Kind = kind;
TextChanges = textChanges;
- Tags = ImmutableArray.Empty;
+ Title = title;
+ Tags = tags;
+ Priority = priority;
+ ProjectReferenceToAdd = projectReferenceToAdd;
+ PortableExecutableReferenceProjectId = portableExecutableReferenceProjectId;
+ PortableExecutableReferenceFilePathToAdd = portableExecutableReferenceFilePathToAdd;
+ AssemblyReferenceAssemblyName = assemblyReferenceAssemblyName;
+ AssemblyReferenceFullyQualifiedTypeName = assemblyReferenceFullyQualifiedTypeName;
+ PackageSource = packageSource;
+ PackageName = packageName;
+ PackageVersionOpt = packageVersionOpt;
}
public static AddImportFixData CreateForProjectSymbol(ImmutableArray textChanges, string title, ImmutableArray tags, CodeActionPriority priority, ProjectId projectReferenceToAdd)
- {
- return new AddImportFixData(AddImportFixKind.ProjectSymbol, textChanges)
- {
- Title = title,
- Tags = tags,
- Priority = priority,
- ProjectReferenceToAdd = projectReferenceToAdd
- };
- }
+ => new(AddImportFixKind.ProjectSymbol,
+ textChanges,
+ title: title,
+ tags: tags,
+ priority: priority,
+ projectReferenceToAdd: projectReferenceToAdd);
public static AddImportFixData CreateForMetadataSymbol(ImmutableArray textChanges, string title, ImmutableArray tags, CodeActionPriority priority, ProjectId portableExecutableReferenceProjectId, string portableExecutableReferenceFilePathToAdd)
- {
- return new AddImportFixData(AddImportFixKind.MetadataSymbol, textChanges)
- {
- Title = title,
- Tags = tags,
- Priority = priority,
- PortableExecutableReferenceProjectId = portableExecutableReferenceProjectId,
- PortableExecutableReferenceFilePathToAdd = portableExecutableReferenceFilePathToAdd
- };
- }
+ => new(AddImportFixKind.MetadataSymbol,
+ textChanges,
+ title: title,
+ tags: tags,
+ priority: priority,
+ portableExecutableReferenceProjectId: portableExecutableReferenceProjectId,
+ portableExecutableReferenceFilePathToAdd: portableExecutableReferenceFilePathToAdd);
public static AddImportFixData CreateForReferenceAssemblySymbol(ImmutableArray textChanges, string title, string assemblyReferenceAssemblyName, string assemblyReferenceFullyQualifiedTypeName)
- {
- return new AddImportFixData(AddImportFixKind.ReferenceAssemblySymbol, textChanges)
- {
- Title = title,
- Tags = WellKnownTagArrays.AddReference,
- Priority = CodeActionPriority.Low,
- AssemblyReferenceAssemblyName = assemblyReferenceAssemblyName,
- AssemblyReferenceFullyQualifiedTypeName = assemblyReferenceFullyQualifiedTypeName
- };
- }
+ => new(AddImportFixKind.ReferenceAssemblySymbol,
+ textChanges,
+ title: title,
+ tags: WellKnownTagArrays.AddReference,
+ priority: CodeActionPriority.Low,
+ assemblyReferenceAssemblyName: assemblyReferenceAssemblyName,
+ assemblyReferenceFullyQualifiedTypeName: assemblyReferenceFullyQualifiedTypeName);
public static AddImportFixData CreateForPackageSymbol(ImmutableArray textChanges, string packageSource, string packageName, string packageVersionOpt)
- {
- return new AddImportFixData(AddImportFixKind.PackageSymbol, textChanges)
- {
- PackageSource = packageSource,
- Priority = CodeActionPriority.Low,
- PackageName = packageName,
- PackageVersionOpt = packageVersionOpt,
- };
- }
+ => new(AddImportFixKind.PackageSymbol,
+ textChanges,
+ packageSource: packageSource,
+ priority: CodeActionPriority.Low,
+ packageName: packageName,
+ packageVersionOpt: packageVersionOpt);
}
}
diff --git a/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs b/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs
index ce7827e4e1849..26cc554d43b2d 100644
--- a/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs
+++ b/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.SymbolSearch;
@@ -24,39 +25,21 @@ internal abstract partial class AbstractAddImportFeatureService
- private sealed class RemoteSymbolSearchService : IRemoteSymbolSearchUpdateEngine
+ private sealed class RemoteAddImportServiceCallback : IRemoteMissingImportDiscoveryService.ICallback
{
private readonly ISymbolSearchService _symbolSearchService;
- public RemoteSymbolSearchService(ISymbolSearchService symbolSearchService)
+ public RemoteAddImportServiceCallback(ISymbolSearchService symbolSearchService)
=> _symbolSearchService = symbolSearchService;
- public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory)
- {
- // Remote side should never call this.
- throw new NotImplementedException();
- }
+ public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken)
+ => _symbolSearchService.FindPackagesWithTypeAsync(source, name, arity, cancellationToken);
- public Task> FindPackagesWithTypeAsync(
- string source, string name, int arity, CancellationToken cancellationToken)
- {
- return _symbolSearchService.FindPackagesWithTypeAsync(
- source, name, arity, cancellationToken);
- }
+ public ValueTask> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken)
+ => _symbolSearchService.FindPackagesWithAssemblyAsync(source, name, cancellationToken);
- public Task> FindPackagesWithAssemblyAsync(
- string source, string name, CancellationToken cancellationToken)
- {
- return _symbolSearchService.FindPackagesWithAssemblyAsync(
- source, name, cancellationToken);
- }
-
- public Task> FindReferenceAssembliesWithTypeAsync(
- string name, int arity, CancellationToken cancellationToken)
- {
- return _symbolSearchService.FindReferenceAssembliesWithTypeAsync(
- name, arity, cancellationToken);
- }
+ public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken)
+ => _symbolSearchService.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken);
}
}
}
diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs
deleted file mode 100644
index acdcf598092d3..0000000000000
--- a/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Packaging;
-using Microsoft.CodeAnalysis.Remote;
-using Microsoft.CodeAnalysis.Text;
-
-namespace Microsoft.CodeAnalysis.AddImport
-{
- internal interface IRemoteAddImportFeatureService
- {
- Task> GetFixesAsync(
- PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, bool placeSystemNamespaceFirst,
- bool searchReferenceAssemblies, IList packageSources, CancellationToken cancellationToken);
- }
-}
diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs
new file mode 100644
index 0000000000000..d9b57e4966f20
--- /dev/null
+++ b/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Packaging;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.SymbolSearch;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.AddImport
+{
+ internal interface IRemoteMissingImportDiscoveryService
+ {
+ internal interface ICallback
+ {
+ ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken);
+ ValueTask> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken);
+ ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken);
+ }
+
+ ValueTask> GetFixesAsync(
+ PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, bool placeSystemNamespaceFirst,
+ bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken);
+ }
+}
diff --git a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs
index f0419302bfa0e..fe28b0551299a 100644
--- a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs
+++ b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Threading;
@@ -23,9 +24,9 @@ internal sealed class CodeLensReferencesService : ICodeLensReferencesService
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
memberOptions: SymbolDisplayMemberOptions.IncludeContainingType);
- private static async Task FindAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
+ private static async Task FindAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
Func> onResults, Func> onCapped,
- int searchCap, CancellationToken cancellationToken) where T : class
+ int searchCap, CancellationToken cancellationToken) where T : struct
{
var document = solution.GetDocument(documentId);
if (document == null)
@@ -65,7 +66,7 @@ await SymbolFinder.FindReferencesAsync(symbol, solution, progress, null,
}
}
- public Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults, CancellationToken cancellationToken)
+ public Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults, CancellationToken cancellationToken)
{
return FindAsync(solution, documentId, syntaxNode,
progress => Task.FromResult(new ReferenceCount(
@@ -180,7 +181,7 @@ private static SyntaxNode GetEnclosingCodeElementNode(Document document, SyntaxT
return langServices.GetDisplayNode(node);
}
- public async Task> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken)
+ public async Task?> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
return await FindAsync(solution, documentId, syntaxNode,
async progress =>
@@ -191,7 +192,7 @@ public async Task> FindReferenceLocatio
var result = await Task.WhenAll(referenceTasks).ConfigureAwait(false);
- return (IEnumerable)result;
+ return result.ToImmutableArray();
}, onCapped: null, searchCap: 0, cancellationToken: cancellationToken).ConfigureAwait(false);
}
@@ -238,7 +239,7 @@ private static async Task TryGetMethodDescriptorAsync
return !string.IsNullOrEmpty(fullName) ? new ReferenceMethodDescriptor(fullName, document.FilePath, document.Project.OutputFilePath) : null;
}
- public Task> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken)
+ public Task?> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
return FindAsync(solution, documentId, syntaxNode,
async progress =>
@@ -250,7 +251,7 @@ public Task> FindReferenceMethodsAsync(So
var result = await Task.WhenAll(descriptorTasks).ConfigureAwait(false);
- return result.OfType();
+ return result.OfType().ToImmutableArray();
}, onCapped: null, searchCap: 0, cancellationToken: cancellationToken);
}
diff --git a/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs
index 4fa7d213438e8..d96dce7f3cefe 100644
--- a/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs
+++ b/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs
@@ -2,7 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
@@ -18,23 +21,21 @@ internal interface ICodeLensReferencesService : IWorkspaceService
/// if is greater than 0.
///
///
- Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults, CancellationToken cancellationToken);
+ Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode, int maxSearchResults, CancellationToken cancellationToken);
///
/// Given a document and syntax node, returns a collection of locations where the located node is referenced.
///
- Task> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken);
+ Task?> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode, CancellationToken cancellationToken);
///
/// Given a document and syntax node, returns a collection of locations of methods that refer to the located node.
///
- Task> FindReferenceMethodsAsync(Solution solution,
- DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken);
+ Task?> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode, CancellationToken cancellationToken);
///
/// Given a document and syntax node, returns the fully qualified name of the located node's declaration.
///
- Task GetFullyQualifiedNameAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
- CancellationToken cancellationToken);
+ Task GetFullyQualifiedNameAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode, CancellationToken cancellationToken);
}
}
diff --git a/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs b/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs
index 2b4bce0def2a7..f4d8259ef4e9c 100644
--- a/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs
+++ b/src/Features/Core/Portable/CodeLens/IRemoteCodeLensReferencesService.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
@@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.CodeLens
{
internal interface IRemoteCodeLensReferencesService
{
- Task GetReferenceCountAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken);
- Task> FindReferenceLocationsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
- Task> FindReferenceMethodsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
- Task GetFullyQualifiedNameAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
+ ValueTask GetReferenceCountAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken);
+ ValueTask?> FindReferenceLocationsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
+ ValueTask?> FindReferenceMethodsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
+ ValueTask GetFullyQualifiedNameAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken);
}
}
diff --git a/src/Features/Core/Portable/CodeLens/ReferenceCount.cs b/src/Features/Core/Portable/CodeLens/ReferenceCount.cs
index 619acedfefc87..d6f73c23cb68b 100644
--- a/src/Features/Core/Portable/CodeLens/ReferenceCount.cs
+++ b/src/Features/Core/Portable/CodeLens/ReferenceCount.cs
@@ -2,21 +2,26 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.CodeLens
{
///
/// Represents the result of a FindReferences Count operation.
///
- internal class ReferenceCount
+ [DataContract]
+ internal readonly struct ReferenceCount
{
///
/// Represents the number of references to a given symbol.
///
+ [DataMember(Order = 0)]
public int Count { get; }
///
/// Represents if the count is capped by a certain maximum.
///
+ [DataMember(Order = 1)]
public bool IsCapped { get; }
public ReferenceCount(int count, bool isCapped)
diff --git a/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs b/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs
index bf11aaba08586..2e3767f4277a3 100644
--- a/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs
+++ b/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs
@@ -3,91 +3,110 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Runtime.Serialization;
namespace Microsoft.CodeAnalysis.CodeLens
{
///
/// Holds information required to display and navigate to individual references
///
+ [DataContract]
internal sealed class ReferenceLocationDescriptor
{
- public Guid ProjectGuid { get; }
+ ///
+ /// Fully qualified name of the symbol containing the reference location
+ ///
+ [DataMember(Order = 0)]
+ public string LongDescription { get; }
- public Guid DocumentGuid { get; }
+ ///
+ /// Language of the reference location
+ ///
+ [DataMember(Order = 1)]
+ public string Language { get; }
///
- /// Document's file path
+ /// The kind of symbol containing the reference location (such as type, method, property, etc.)
///
- public string FilePath { get; }
+ [DataMember(Order = 2)]
+ public Glyph? Glyph { get; }
///
/// Reference's span start based on the document content
///
+ [DataMember(Order = 3)]
public int SpanStart { get; }
///
/// Reference's span length based on the document content
///
+ [DataMember(Order = 4)]
public int SpanLength { get; }
///
/// Reference's line based on the document content
///
+ [DataMember(Order = 5)]
public int LineNumber { get; }
///
/// Reference's character based on the document content
///
+ [DataMember(Order = 6)]
public int ColumnNumber { get; }
- ///
- /// Language of the reference location
- ///
- public string Language { get; }
+ [DataMember(Order = 7)]
+ public Guid ProjectGuid { get; }
- ///
- /// Fully qualified name of the symbol containing the reference location
- ///
- public string LongDescription { get; }
+ [DataMember(Order = 8)]
+ public Guid DocumentGuid { get; }
///
- /// The kind of symbol containing the reference location (such as type, method, property, etc.)
+ /// Document's file path
///
- public Glyph? Glyph { get; }
+ [DataMember(Order = 9)]
+ public string FilePath { get; }
///
/// the full line of source that contained the reference
///
+ [DataMember(Order = 10)]
public string ReferenceLineText { get; }
///
/// the beginning of the span within reference text that was the use of the reference
///
+ [DataMember(Order = 11)]
public int ReferenceStart { get; }
///
/// the length of the span of the reference
///
+ [DataMember(Order = 12)]
public int ReferenceLength { get; }
///
/// Text above the line with the reference
///
+ [DataMember(Order = 13)]
public string BeforeReferenceText1 { get; }
///
/// Text above the line with the reference
///
+ [DataMember(Order = 14)]
public string BeforeReferenceText2 { get; }
///
/// Text below the line with the reference
///
+ [DataMember(Order = 15)]
public string AfterReferenceText1 { get; }
///
/// Text below the line with the reference
///
+ [DataMember(Order = 16)]
public string AfterReferenceText2 { get; }
public ReferenceLocationDescriptor(
diff --git a/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs b/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs
index 1d686c6a876dd..482056798494d 100644
--- a/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs
+++ b/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs
@@ -2,13 +2,34 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.CodeLens
{
///
/// A caller method of a callee
///
+ [DataContract]
internal sealed class ReferenceMethodDescriptor
{
+ ///
+ /// Returns method's fully quilified name without parameters
+ ///
+ [DataMember(Order = 0)]
+ public string FullName { get; private set; }
+
+ ///
+ /// Returns method's file path.
+ ///
+ [DataMember(Order = 1)]
+ public string FilePath { get; private set; }
+
+ ///
+ /// Returns output file path for the project containing the method.
+ ///
+ [DataMember(Order = 2)]
+ public string OutputFilePath { get; private set; }
+
///
/// Describe a caller method of a callee
///
@@ -24,20 +45,5 @@ public ReferenceMethodDescriptor(string fullName, string filePath, string output
FilePath = filePath;
OutputFilePath = outputFilePath;
}
-
- ///
- /// Returns method's fully quilified name without parameters
- ///
- public string FullName { get; private set; }
-
- ///
- /// Returns method's file path.
- ///
- public string FilePath { get; private set; }
-
- ///
- /// Returns output file path for the project containing the method.
- ///
- public string OutputFilePath { get; private set; }
}
}
diff --git a/src/Features/Core/Portable/Common/TaggedText.cs b/src/Features/Core/Portable/Common/TaggedText.cs
index 4ea3b8d125e7b..65405868ae02f 100644
--- a/src/Features/Core/Portable/Common/TaggedText.cs
+++ b/src/Features/Core/Portable/Common/TaggedText.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
@@ -16,33 +17,39 @@ namespace Microsoft.CodeAnalysis
///
/// A piece of text with a descriptive tag.
///
+ [DataContract]
public readonly struct TaggedText
{
///
/// A descriptive tag from .
///
+ [DataMember(Order = 0)]
public string Tag { get; }
///
/// The actual text to be displayed.
///
+ [DataMember(Order = 1)]
public string Text { get; }
///
/// Gets the style(s) to apply to the text.
///
+ [DataMember(Order = 2)]
internal TaggedTextStyle Style { get; }
///
/// Gets the navigation target for the text, or if the text does not have a navigation
/// target.
///
+ [DataMember(Order = 3)]
internal string NavigationTarget { get; }
///
/// Gets the navigation hint for the text, or if the text does not have a navigation
/// hint.
///
+ [DataMember(Order = 4)]
internal string NavigationHint { get; }
///
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
index 1e920cb0e1b34..4368a910cce6d 100644
--- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs
@@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion.Log;
@@ -35,39 +34,52 @@ public static async Task> GetUn
bool forceIndexCreation,
CancellationToken cancellationToken)
{
- async Task<(ImmutableArray, StatisticCounter)> GetItemsAsync()
+ SerializableUnimportedExtensionMethods items;
+
+ var ticks = Environment.TickCount;
+
+ var project = document.Project;
+ var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);
+ if (client != null)
{
- var project = document.Project;
+ var receiverTypeSymbolKeyData = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken);
- var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);
- if (client != null)
+ var result = await client.TryInvokeAsync(
+ project.Solution,
+ (service, solutionInfo, cancellationToken) => service.GetUnimportedExtensionMethodsAsync(
+ solutionInfo, document.Id, position, receiverTypeSymbolKeyData, namespaceInScope.ToImmutableArray(), forceIndexCreation, cancellationToken),
+ callbackTarget: null,
+ cancellationToken).ConfigureAwait(false);
+
+ if (!result.HasValue)
{
- var result = await client.RunRemoteAsync<(IList items, StatisticCounter counter)>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteExtensionMethodImportCompletionService.GetUnimportedExtensionMethodsAsync),
- project.Solution,
- new object[] { document.Id, position, SymbolKey.CreateString(receiverTypeSymbol, cancellationToken), namespaceInScope.ToArray(), forceIndexCreation },
- callbackTarget: null,
- cancellationToken).ConfigureAwait(false);
-
- return (result.items.ToImmutableArray(), result.counter);
+ return ImmutableArray.Empty;
}
- return await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false);
+ items = result.Value;
+ }
+ else
+ {
+ items = await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false);
}
- var ticks = Environment.TickCount;
+ // report telemetry:
+ var totalTicks = Environment.TickCount - ticks;
- var (items, counter) = await GetItemsAsync().ConfigureAwait(false);
+ CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(totalTicks);
+ CompletionProvidersLogger.LogExtensionMethodCompletionMethodsProvidedDataPoint(items.CompletionItems.Length);
+ CompletionProvidersLogger.LogExtensionMethodCompletionGetSymbolsTicksDataPoint(items.GetSymbolsTicks);
+ CompletionProvidersLogger.LogExtensionMethodCompletionCreateItemsTicksDataPoint(items.CreateItemsTicks);
- counter.TotalTicks = Environment.TickCount - ticks;
- counter.TotalExtensionMethodsProvided = items.Length;
- counter.Report();
+ if (items.IsPartialResult)
+ {
+ CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount();
+ }
- return items;
+ return items.CompletionItems;
}
- public static async Task<(ImmutableArray, StatisticCounter)> GetUnimportedExtensionMethodsInCurrentProcessAsync(
+ public static async Task GetUnimportedExtensionMethodsInCurrentProcessAsync(
Document document,
int position,
ITypeSymbol receiverTypeSymbol,
@@ -75,7 +87,6 @@ public static async Task> GetUn
bool forceIndexCreation,
CancellationToken cancellationToken)
{
- var counter = new StatisticCounter();
var ticks = Environment.TickCount;
// First find symbols of all applicable extension methods.
@@ -84,7 +95,7 @@ public static async Task> GetUn
document, position, receiverTypeSymbol, namespaceInScope, cancellationToken).ConfigureAwait(false);
var (extentsionMethodSymbols, isPartialResult) = await symbolComputer.GetExtensionMethodSymbolsAsync(forceIndexCreation, cancellationToken).ConfigureAwait(false);
- counter.GetSymbolsTicks = Environment.TickCount - ticks;
+ var getSymbolsTicks = Environment.TickCount - ticks;
ticks = Environment.TickCount;
var items = ConvertSymbolsToCompletionItems(extentsionMethodSymbols, cancellationToken);
@@ -103,13 +114,11 @@ public static async Task> GetUn
s_indexingTask = symbolComputer.PopulateIndicesAsync(CancellationToken.None);
}
}
-
- counter.PartialResult = true;
}
- counter.CreateItemsTicks = Environment.TickCount - ticks;
+ var createItemsTicks = Environment.TickCount - ticks;
- return (items, counter);
+ return new SerializableUnimportedExtensionMethods(items, isPartialResult, getSymbolsTicks, createItemsTicks);
}
@@ -179,26 +188,4 @@ private static string GetFullyQualifiedNamespaceName(INamespaceSymbol symbol, Di
return name;
}
}
-
- internal sealed class StatisticCounter
- {
- public bool PartialResult { get; set; }
- public int TotalTicks { get; set; }
- public int TotalExtensionMethodsProvided { get; set; }
- public int GetSymbolsTicks { get; set; }
- public int CreateItemsTicks { get; set; }
-
- public void Report()
- {
- CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(TotalTicks);
- CompletionProvidersLogger.LogExtensionMethodCompletionMethodsProvidedDataPoint(TotalExtensionMethodsProvided);
- CompletionProvidersLogger.LogExtensionMethodCompletionGetSymbolsTicksDataPoint(GetSymbolsTicks);
- CompletionProvidersLogger.LogExtensionMethodCompletionCreateItemsTicksDataPoint(CreateItemsTicks);
-
- if (PartialResult)
- {
- CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount();
- }
- }
- }
}
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IRemoteExtensionMethodImportCompletionService.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IRemoteExtensionMethodImportCompletionService.cs
index f80674e78bfea..6beb28a16c334 100644
--- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IRemoteExtensionMethodImportCompletionService.cs
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/IRemoteExtensionMethodImportCompletionService.cs
@@ -4,7 +4,7 @@
#nullable enable
-using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
@@ -13,12 +13,12 @@ namespace Microsoft.CodeAnalysis.Completion.Providers
{
internal interface IRemoteExtensionMethodImportCompletionService
{
- Task<(IList, StatisticCounter)> GetUnimportedExtensionMethodsAsync(
+ public ValueTask GetUnimportedExtensionMethodsAsync(
PinnedSolutionInfo solutionInfo,
DocumentId documentId,
int position,
string receiverTypeSymbolKeyData,
- string[] namespaceInScope,
+ ImmutableArray namespaceInScope,
bool forceIndexCreation,
CancellationToken cancellationToken);
}
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs
index a6586b3ad1fc3..405e8e950b5d7 100644
--- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs
@@ -4,15 +4,29 @@
#nullable enable
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.Completion.Providers
{
+ [DataContract]
internal readonly struct SerializableImportCompletionItem
{
+ [DataMember(Order = 0)]
public readonly string SymbolKeyData;
- public readonly int Arity;
+
+ [DataMember(Order = 1)]
public readonly string Name;
+
+ [DataMember(Order = 2)]
+ public readonly int Arity;
+
+ [DataMember(Order = 3)]
public readonly Glyph Glyph;
+
+ [DataMember(Order = 4)]
public readonly string ContainingNamespace;
+
+ [DataMember(Order = 5)]
public readonly int AdditionalOverloadCount;
public SerializableImportCompletionItem(string symbolKeyData, string name, int arity, Glyph glyph, string containingNamespace, int additionalOverloadCount)
diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs
new file mode 100644
index 0000000000000..f6c574acb8acc
--- /dev/null
+++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Runtime.Serialization;
+
+namespace Microsoft.CodeAnalysis.Completion.Providers
+{
+ [DataContract]
+ internal readonly struct SerializableUnimportedExtensionMethods
+ {
+ [DataMember(Order = 0)]
+ public readonly ImmutableArray CompletionItems;
+
+ [DataMember(Order = 1)]
+ public readonly bool IsPartialResult;
+
+ [DataMember(Order = 2)]
+ public readonly int GetSymbolsTicks;
+
+ [DataMember(Order = 3)]
+ public readonly int CreateItemsTicks;
+
+ public SerializableUnimportedExtensionMethods(
+ ImmutableArray completionItems,
+ bool isPartialResult,
+ int getSymbolsTicks,
+ int createItemsTicks)
+ {
+ CompletionItems = completionItems;
+ IsPartialResult = isPartialResult;
+ GetSymbolsTicks = getSymbolsTicks;
+ CreateItemsTicks = createItemsTicks;
+ }
+ }
+}
diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs
index 2508ba8595e3a..94599f1a20489 100644
--- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs
+++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs
@@ -168,24 +168,22 @@ public async Task ConvertToStructAsync(
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteConvertTupleToStructCodeRefactoringProvider.ConvertToStructAsync),
+ var result = await client.TryInvokeAsync(
solution,
- new object[]
- {
- document.Id,
- span,
- scope,
- },
+ (service, solutionInfo, cancellationToken) => service.ConvertToStructAsync(solutionInfo, document.Id, span, scope, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return solution;
+ }
+
var resultSolution = await RemoteUtilities.UpdateSolutionAsync(
- solution, result.DocumentTextChanges, cancellationToken).ConfigureAwait(false);
+ solution, result.Value.DocumentTextChanges, cancellationToken).ConfigureAwait(false);
return await AddRenameTokenAsync(
- resultSolution, result.RenamedToken, cancellationToken).ConfigureAwait(false);
+ resultSolution, result.Value.RenamedToken, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs
deleted file mode 100644
index ddeaaab4772ae..0000000000000
--- a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Remote;
-using Microsoft.CodeAnalysis.Text;
-
-namespace Microsoft.CodeAnalysis.ConvertTupleToStruct
-{
- internal interface IRemoteConvertTupleToStructCodeRefactoringProvider
- {
- Task ConvertToStructAsync(
- PinnedSolutionInfo solutionInfo,
- DocumentId documentId,
- TextSpan span,
- Scope scope,
- CancellationToken cancellationToken);
- }
-
- internal class SerializableConvertTupleToStructResult
- {
- public (DocumentId, TextChange[])[] DocumentTextChanges;
- public (DocumentId, TextSpan) RenamedToken;
- }
-}
diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs
new file mode 100644
index 0000000000000..c5c290b8826ea
--- /dev/null
+++ b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.ConvertTupleToStruct
+{
+ internal interface IRemoteConvertTupleToStructCodeRefactoringService
+ {
+ ValueTask ConvertToStructAsync(
+ PinnedSolutionInfo solutionInfo,
+ DocumentId documentId,
+ TextSpan span,
+ Scope scope,
+ CancellationToken cancellationToken);
+ }
+
+ [DataContract]
+ internal readonly struct SerializableConvertTupleToStructResult
+ {
+ [DataMember(Order = 0)]
+ public readonly ImmutableArray<(DocumentId, ImmutableArray)> DocumentTextChanges;
+
+ [DataMember(Order = 1)]
+ public readonly (DocumentId, TextSpan) RenamedToken;
+
+ public SerializableConvertTupleToStructResult(
+ ImmutableArray<(DocumentId, ImmutableArray)> documentTextChanges,
+ (DocumentId, TextSpan) renamedToken)
+ {
+ DocumentTextChanges = documentTextChanges;
+ RenamedToken = renamedToken;
+ }
+ }
+}
diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs
index 935d6da138210..f301b126f4b97 100644
--- a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs
+++ b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs
@@ -5,6 +5,7 @@
#nullable enable
using System.Diagnostics;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Diagnostics
@@ -12,6 +13,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics
///
/// helper type to package diagnostic arguments to pass around between remote hosts
///
+ [DataContract]
internal class DiagnosticArguments
{
///
@@ -20,35 +22,41 @@ internal class DiagnosticArguments
/// Additionally, diagnostic computation for explicit user commands, such as FixAll,
/// are marked high priority.
///
+ [DataMember(Order = 0)]
public bool IsHighPriority;
///
/// Flag indicating if suppressed diagnostics should be returned.
///
+ [DataMember(Order = 1)]
public bool ReportSuppressedDiagnostics;
///
/// Flag indicating if analyzer performance info, such as analyzer execution times,
/// should be logged as performance telemetry.
///
+ [DataMember(Order = 2)]
public bool LogPerformanceInfo;
///
/// Flag indicating if the analyzer telemety info, such as registered analyzer action counts
/// and analyzer execution times, should be included in the computed result.
///
+ [DataMember(Order = 3)]
public bool GetTelemetryInfo;
///
/// Optional document ID, if computing diagnostics for a specific document.
/// For example, diagnostic computation for open file analysis.
///
+ [DataMember(Order = 4)]
public DocumentId? DocumentId;
///
/// Optional document text span, if computing diagnostics for a specific span for a document.
/// For example, diagnostic computation for light bulb invocation for a specific line in active document.
///
+ [DataMember(Order = 5)]
public TextSpan? DocumentSpan;
///
@@ -56,16 +64,19 @@ internal class DiagnosticArguments
/// i.e. must be non-null for a non-null analysis kind.
/// Only supported non-null values are and .
///
+ [DataMember(Order = 6)]
public AnalysisKind? DocumentAnalysisKind;
///
/// Project ID for the document or project for which diagnostics need to be computed.
///
+ [DataMember(Order = 7)]
public ProjectId ProjectId;
///
/// Array of analyzer IDs for analyzers that need to be executed for computing diagnostics.
///
+ [DataMember(Order = 8)]
public string[] AnalyzerIds;
public DiagnosticArguments(
diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticResultSerializer.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticResultSerializer.cs
deleted file mode 100644
index 5e5cd7f37eec5..0000000000000
--- a/src/Features/Core/Portable/Diagnostics/DiagnosticResultSerializer.cs
+++ /dev/null
@@ -1,308 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#nullable enable
-
-using System;
-using System.Diagnostics;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Threading;
-using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
-using Microsoft.CodeAnalysis.Host;
-using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
-using Roslyn.Utilities;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.CodeAnalysis.ErrorReporting;
-
-namespace Microsoft.CodeAnalysis.Diagnostics
-{
- internal static class DiagnosticResultSerializer
- {
- public static (int diagnostics, int telemetry) WriteDiagnosticAnalysisResults(
- ObjectWriter writer,
- AnalysisKind? analysisKind,
- DiagnosticAnalysisResultMap result,
- CancellationToken cancellationToken)
- {
- var diagnosticCount = 0;
- var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
-
- writer.WriteInt32(result.AnalysisResult.Count);
- foreach (var (analyzerId, analyzerResults) in result.AnalysisResult)
- {
- writer.WriteString(analyzerId);
-
- switch (analysisKind)
- {
- case AnalysisKind.Syntax:
- diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SyntaxLocals, cancellationToken);
- break;
-
- case AnalysisKind.Semantic:
- diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SemanticLocals, cancellationToken);
- break;
-
- case null:
- diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SyntaxLocals, cancellationToken);
- diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SemanticLocals, cancellationToken);
- diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.NonLocals, cancellationToken);
-
- diagnosticSerializer.WriteDiagnosticData(writer, analyzerResults.Others, cancellationToken);
- diagnosticCount += analyzerResults.Others.Length;
- break;
-
- default:
- throw ExceptionUtilities.UnexpectedValue(analysisKind.Value);
- }
- }
-
- writer.WriteInt32(result.TelemetryInfo.Count);
- foreach (var (analyzerId, analyzerTelemetry) in result.TelemetryInfo)
- {
- writer.WriteString(analyzerId);
- WriteTelemetry(writer, analyzerTelemetry, cancellationToken);
- }
-
- // report how many data has been sent
- return (diagnosticCount, result.TelemetryInfo.Count);
- }
-
- public static bool TryReadDiagnosticAnalysisResults(
- ObjectReader reader,
- IDictionary analyzerMap,
- DocumentAnalysisScope? documentAnalysisScope,
- Project project,
- VersionStamp version,
- CancellationToken cancellationToken,
- [NotNullWhen(returnValue: true)] out DiagnosticAnalysisResultMap? result)
- {
- result = null;
-
- try
- {
- var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);
-
- var analysisMap = ImmutableDictionary.CreateBuilder();
- var documentIds = documentAnalysisScope != null ? ImmutableHashSet.Create(documentAnalysisScope.TextDocument.Id) : null;
-
- var analysisCount = reader.ReadInt32();
- for (var i = 0; i < analysisCount; i++)
- {
- var analyzer = analyzerMap[reader.ReadString()];
-
- DiagnosticAnalysisResult analysisResult;
- if (documentAnalysisScope != null)
- {
- ImmutableDictionary>? syntaxLocalMap, semanticLocalMap;
- if (documentAnalysisScope.Kind == AnalysisKind.Syntax)
- {
- if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out syntaxLocalMap))
- {
- return false;
- }
-
- semanticLocalMap = ImmutableDictionary>.Empty;
- }
- else
- {
- Debug.Assert(documentAnalysisScope.Kind == AnalysisKind.Semantic);
- if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out semanticLocalMap))
- {
- return false;
- }
-
- syntaxLocalMap = ImmutableDictionary>.Empty;
- }
-
- analysisResult = DiagnosticAnalysisResult.Create(
- project,
- version,
- syntaxLocalMap,
- semanticLocalMap,
- nonLocalMap: ImmutableDictionary>.Empty,
- others: ImmutableArray.Empty,
- documentIds);
- }
- else
- {
- if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var syntaxLocalMap) ||
- !TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var semanticLocalMap) ||
- !TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var nonLocalMap) ||
- !diagnosticDataSerializer.TryReadDiagnosticData(reader, project, document: null, cancellationToken, out var others))
- {
- return false;
- }
-
- analysisResult = DiagnosticAnalysisResult.Create(
- project,
- version,
- syntaxLocalMap,
- semanticLocalMap,
- nonLocalMap,
- others.NullToEmpty(),
- documentIds: null);
- }
-
- 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 = ReadTelemetry(reader, cancellationToken);
-
- telemetryMap.Add(analyzer, telemetryInfo);
- }
-
- result = DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable());
- return true;
- }
- catch (Exception ex) when (FatalError.ReportWithoutCrashUnlessCanceled(ex))
- {
- return false;
- }
- }
-
- private static int WriteDiagnosticDataMap(
- ObjectWriter writer,
- DiagnosticDataSerializer serializer,
- ImmutableDictionary> diagnostics,
- CancellationToken cancellationToken)
- {
- var count = 0;
-
- writer.WriteInt32(diagnostics.Count);
- foreach (var (documentId, data) in diagnostics)
- {
- documentId.WriteTo(writer);
- serializer.WriteDiagnosticData(writer, data, cancellationToken);
-
- count += data.Length;
- }
-
- return count;
- }
-
- private static bool TryReadDiagnosticDataMap(
- ObjectReader reader,
- DiagnosticDataSerializer serializer,
- Project project,
- CancellationToken cancellationToken,
- [NotNullWhen(returnValue: true)] out ImmutableDictionary>? dataMap)
- {
- var count = reader.ReadInt32();
-
- var map = ImmutableDictionary.CreateBuilder>();
- for (var i = 0; i < count; i++)
- {
- var documentId = DocumentId.ReadFrom(reader);
- var document = project.GetDocument(documentId);
-
- if (!serializer.TryReadDiagnosticData(reader, project, document, cancellationToken, out var diagnostics))
- {
- dataMap = null;
- return false;
- }
-
- // drop diagnostics for non-null document that doesn't support diagnostics
- if (diagnostics.IsDefault || document?.SupportsDiagnostics() == false)
- {
- continue;
- }
-
- map.Add(documentId, diagnostics);
- }
-
- dataMap = map.ToImmutable();
- return true;
- }
-
- private static void WriteTelemetry(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.AdditionalFileActionsCount);
- writer.WriteInt32(telemetryInfo.SemanticModelActionsCount);
- writer.WriteInt32(telemetryInfo.SymbolActionsCount);
- writer.WriteInt32(telemetryInfo.SymbolStartActionsCount);
- writer.WriteInt32(telemetryInfo.SymbolEndActionsCount);
- 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.WriteInt32(telemetryInfo.SuppressionActionsCount);
- writer.WriteInt64(telemetryInfo.ExecutionTime.Ticks);
- writer.WriteBoolean(telemetryInfo.Concurrent);
- }
-
- private static AnalyzerTelemetryInfo ReadTelemetry(ObjectReader reader, CancellationToken cancellationToken)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var compilationStartActionsCount = reader.ReadInt32();
- var compilationEndActionsCount = reader.ReadInt32();
- var compilationActionsCount = reader.ReadInt32();
- var syntaxTreeActionsCount = reader.ReadInt32();
- var additionalFileActionsCount = reader.ReadInt32();
- var semanticModelActionsCount = reader.ReadInt32();
- var symbolActionsCount = reader.ReadInt32();
- var symbolStartActionsCount = reader.ReadInt32();
- var symbolEndActionsCount = 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 suppressionActionsCount = reader.ReadInt32();
- var executionTime = new TimeSpan(reader.ReadInt64());
- var concurrent = reader.ReadBoolean();
-
- return new AnalyzerTelemetryInfo()
- {
- CompilationStartActionsCount = compilationStartActionsCount,
- CompilationEndActionsCount = compilationEndActionsCount,
- CompilationActionsCount = compilationActionsCount,
-
- SyntaxTreeActionsCount = syntaxTreeActionsCount,
- AdditionalFileActionsCount = additionalFileActionsCount,
- SemanticModelActionsCount = semanticModelActionsCount,
- SymbolActionsCount = symbolActionsCount,
- SymbolStartActionsCount = symbolStartActionsCount,
- SymbolEndActionsCount = symbolEndActionsCount,
- SyntaxNodeActionsCount = syntaxNodeActionsCount,
-
- CodeBlockStartActionsCount = codeBlockStartActionsCount,
- CodeBlockEndActionsCount = codeBlockEndActionsCount,
- CodeBlockActionsCount = codeBlockActionsCount,
-
- OperationActionsCount = operationActionsCount,
- OperationBlockStartActionsCount = operationBlockStartActionsCount,
- OperationBlockEndActionsCount = operationBlockEndActionsCount,
- OperationBlockActionsCount = operationBlockActionsCount,
-
- SuppressionActionsCount = suppressionActionsCount,
-
- ExecutionTime = executionTime,
-
- Concurrent = concurrent
- };
- }
- }
-}
diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
index 1c75b8df462b4..60642c068f25f 100644
--- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
+++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs
@@ -15,7 +15,9 @@
using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Microsoft.CodeAnalysis.ErrorReporting;
+using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;
@@ -192,39 +194,40 @@ private async Task>(
+ var result = await client.TryInvokeAsync(
solution,
- invocation: (service, solutionInfo, stream, cancellationToken) => service.CalculateDiagnosticsAsync(solutionInfo, argument, stream, cancellationToken),
- reader: (stream, cancellationToken) => ReadCompilerAnalysisResultAsync(stream, analyzerMap, documentAnalysisScope, project, cancellationToken),
+ invocation: (service, solutionInfo, cancellationToken) => service.CalculateDiagnosticsAsync(solutionInfo, argument, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return result.HasValue ? result.Value : DiagnosticAnalysisResultMap.Empty;
- }
-
- private static async ValueTask> ReadCompilerAnalysisResultAsync(
- Stream stream,
- Dictionary analyzerMap,
- DocumentAnalysisScope? documentAnalysisScope,
- Project project,
- CancellationToken cancellationToken)
- {
- // handling of cancellation and exception
- var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
-
- using var reader = ObjectReader.TryGetReader(stream, leaveOpen: false, cancellationToken);
-
- // We only get a reader for data transmitted between live processes.
- // This data should always be correct as we're never persisting the data between sessions.
- Contract.ThrowIfNull(reader);
-
- if (!DiagnosticResultSerializer.TryReadDiagnosticAnalysisResults(reader, analyzerMap,
- documentAnalysisScope, project, version, cancellationToken, out var result))
+ if (!result.HasValue)
{
return DiagnosticAnalysisResultMap.Empty;
}
- return result.Value;
+ // handling of cancellation and exception
+ var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);
+
+ var documentIds = (documentAnalysisScope != null) ? ImmutableHashSet.Create(documentAnalysisScope.TextDocument.Id) : null;
+
+ return new DiagnosticAnalysisResultMap(
+ result.Value.Diagnostics.ToImmutableDictionary(
+ entry => analyzerMap[entry.analyzerId],
+ entry => DiagnosticAnalysisResult.Create(
+ project,
+ version,
+ syntaxLocalMap: Hydrate(entry.diagnosticMap.Syntax, project),
+ semanticLocalMap: Hydrate(entry.diagnosticMap.Semantic, project),
+ nonLocalMap: Hydrate(entry.diagnosticMap.NonLocal, project),
+ others: entry.diagnosticMap.Other,
+ documentIds)),
+ result.Value.Telemetry.ToImmutableDictionary(entry => analyzerMap[entry.analyzerId], entry => entry.telemetry));
}
+
+ // TODO: filter in OOP https://github.com/dotnet/roslyn/issues/47859
+ private static ImmutableDictionary> Hydrate(ImmutableArray<(DocumentId documentId, ImmutableArray diagnostics)> diagnosticByDocument, Project project)
+ => diagnosticByDocument
+ .Where(entry => project.GetTextDocument(entry.documentId)?.SupportsDiagnostics() == true)
+ .ToImmutableDictionary(entry => entry.documentId, entry => entry.diagnostics);
}
}
diff --git a/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs
index aba822012e040..2bfd5bf7fe1ec 100644
--- a/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs
+++ b/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
@@ -14,19 +15,25 @@ namespace Microsoft.CodeAnalysis.Diagnostics
{
internal interface IRemoteDiagnosticAnalyzerService
{
- ValueTask CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, Stream outputStream, CancellationToken cancellationToken);
+ ValueTask CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, CancellationToken cancellationToken);
ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray snapshot, int unitCount, CancellationToken cancellationToken);
}
+ [DataContract]
internal readonly struct AnalyzerPerformanceInfo
{
+ [DataMember(Order = 0)]
public readonly string AnalyzerId;
+
+ [DataMember(Order = 1)]
public readonly bool BuiltIn;
+
+ [DataMember(Order = 2)]
public readonly TimeSpan TimeSpan;
- public AnalyzerPerformanceInfo(string analyzerid, bool builtIn, TimeSpan timeSpan)
+ public AnalyzerPerformanceInfo(string analyzerId, bool builtIn, TimeSpan timeSpan)
{
- AnalyzerId = analyzerid;
+ AnalyzerId = analyzerId;
BuiltIn = builtIn;
TimeSpan = timeSpan;
}
diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
index 434cdc710fd55..a82808dd0be57 100644
--- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
+++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs
@@ -30,20 +30,18 @@ public async Task> GetDocumentHighlightsAsync
var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteDocumentHighlights.GetDocumentHighlightsAsync),
+ var result = await client.TryInvokeAsync>(
solution,
- new object[]
- {
- document.Id,
- position,
- documentsToSearch.Select(d => d.Id).ToArray()
- },
+ (service, solutionInfo, cancellationToken) => service.GetDocumentHighlightsAsync(solutionInfo, document.Id, position, documentsToSearch.SelectAsArray(d => d.Id), cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return result.SelectAsArray(h => h.Rehydrate(solution));
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return result.Value.SelectAsArray(h => h.Rehydrate(solution));
}
return await GetDocumentHighlightsInCurrentProcessAsync(
@@ -100,19 +98,6 @@ private static async Task> TryGetEmbeddedLang
return default;
}
- private static async Task GetSymbolToSearchAsync(Document document, int position, SemanticModel semanticModel, ISymbol symbol, CancellationToken cancellationToken)
- {
- // see whether we can use the symbol as it is
- var currentSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
- if (currentSemanticModel == semanticModel)
- {
- return symbol;
- }
-
- // get symbols from current document again
- return await SymbolFinder.FindSymbolAtPositionAsync(currentSemanticModel, position, document.Project.Solution.Workspace, cancellationToken).ConfigureAwait(false);
- }
-
private async Task> GetTagsForReferencedSymbolAsync(
ISymbol symbol,
Document document,
@@ -124,7 +109,7 @@ private async Task> GetTagsForReferencedSymbo
{
var progress = new StreamingProgressCollector();
- var options = FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol);
+ var options = FindSymbols.FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol);
await SymbolFinder.FindReferencesAsync(
symbol, document.Project.Solution, progress,
documentsToSearch, options, cancellationToken).ConfigureAwait(false);
@@ -164,7 +149,7 @@ private static bool ShouldConsiderSymbol(ISymbol symbol)
private async Task> FilterAndCreateSpansAsync(
ImmutableArray references, Document startingDocument,
IImmutableSet documentsToSearch, ISymbol symbol,
- FindReferencesSearchOptions options, CancellationToken cancellationToken)
+ FindSymbols.FindReferencesSearchOptions options, CancellationToken cancellationToken)
{
var solution = startingDocument.Project.Solution;
references = references.FilterToItemsToShow(options);
diff --git a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs
index ff50706ebc97c..9d49416dcbca8 100644
--- a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs
+++ b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
@@ -18,9 +19,13 @@ internal enum HighlightSpanKind
WrittenReference,
}
+ [DataContract]
internal readonly struct HighlightSpan
{
+ [DataMember(Order = 0)]
public TextSpan TextSpan { get; }
+
+ [DataMember(Order = 1)]
public HighlightSpanKind Kind { get; }
public HighlightSpan(TextSpan textSpan, HighlightSpanKind kind) : this()
diff --git a/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlights.cs b/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlights.cs
deleted file mode 100644
index 279a0b6359e35..0000000000000
--- a/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlights.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Remote;
-
-namespace Microsoft.CodeAnalysis.DocumentHighlighting
-{
- internal interface IRemoteDocumentHighlights
- {
- Task> GetDocumentHighlightsAsync(
- PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, DocumentId[] documentIdsToSearch, CancellationToken cancellationToken);
- }
-
- internal struct SerializableDocumentHighlights
- {
- public DocumentId DocumentId;
- public IList HighlightSpans;
-
- public DocumentHighlights Rehydrate(Solution solution)
- => new DocumentHighlights(solution.GetDocument(DocumentId), HighlightSpans.ToImmutableArray());
-
- public static SerializableDocumentHighlights Dehydrate(DocumentHighlights highlights)
- => new SerializableDocumentHighlights
- {
- DocumentId = highlights.Document.Id,
- HighlightSpans = highlights.HighlightSpans
- };
- }
-}
diff --git a/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlightsService.cs
new file mode 100644
index 0000000000000..1a22573e933ce
--- /dev/null
+++ b/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlightsService.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Remote;
+
+namespace Microsoft.CodeAnalysis.DocumentHighlighting
+{
+ internal interface IRemoteDocumentHighlightsService
+ {
+ ValueTask> GetDocumentHighlightsAsync(
+ PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, ImmutableArray documentIdsToSearch, CancellationToken cancellationToken);
+ }
+
+ [DataContract]
+ internal readonly struct SerializableDocumentHighlights
+ {
+ [DataMember(Order = 0)]
+ public readonly DocumentId DocumentId;
+
+ [DataMember(Order = 1)]
+ public readonly ImmutableArray HighlightSpans;
+
+ public SerializableDocumentHighlights(DocumentId documentId, ImmutableArray highlightSpans)
+ {
+ DocumentId = documentId;
+ HighlightSpans = highlightSpans;
+ }
+
+ public DocumentHighlights Rehydrate(Solution solution)
+ => new DocumentHighlights(solution.GetDocument(DocumentId), HighlightSpans);
+
+ public static SerializableDocumentHighlights Dehydrate(DocumentHighlights highlights)
+ => new(highlights.Document.Id, highlights.HighlightSpans);
+ }
+}
diff --git a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs
index 6ebb8f0c51112..2fa6a0702b07d 100644
--- a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs
+++ b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs
@@ -104,21 +104,21 @@ public async Task EncapsulateFieldsAsync(
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync<(DocumentId, TextChange[])[]>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteEncapsulateFieldService.EncapsulateFieldsAsync),
+ var fieldSymbolKeys = fields.SelectAsArray(f => SymbolKey.CreateString(f, cancellationToken));
+
+ var result = await client.TryInvokeAsync)>>(
solution,
- new object[]
- {
- document.Id,
- fields.Select(f => SymbolKey.CreateString(f, cancellationToken)).ToArray(),
- updateReferences,
- },
+ (service, solutionInfo, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, document.Id, fieldSymbolKeys, updateReferences, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return solution;
+ }
+
return await RemoteUtilities.UpdateSolutionAsync(
- solution, result, cancellationToken).ConfigureAwait(false);
+ solution, result.Value, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs
index e1edfef47f965..8b7429f51a135 100644
--- a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs
+++ b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs
@@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.EncapsulateField
{
internal interface IRemoteEncapsulateFieldService
{
- Task<(DocumentId, TextChange[])[]> EncapsulateFieldsAsync(
+ ValueTask)>> EncapsulateFieldsAsync(
PinnedSolutionInfo solutionInfo,
DocumentId documentId,
ImmutableArray fieldSymbolKeys,
diff --git a/src/EditorFeatures/Core/FindUsages/IFindUsagesContext.cs b/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs
similarity index 76%
rename from src/EditorFeatures/Core/FindUsages/IFindUsagesContext.cs
rename to src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs
index fe9d1f09a936e..c57d9b9ed4356 100644
--- a/src/EditorFeatures/Core/FindUsages/IFindUsagesContext.cs
+++ b/src/Features/Core/Portable/FindUsages/IFindUsagesContext.cs
@@ -22,17 +22,17 @@ internal interface IFindUsagesContext
///
/// Report a message to be displayed to the user.
///
- Task ReportMessageAsync(string message);
+ ValueTask ReportMessageAsync(string message);
///
/// Set the title of the window that results are displayed in.
///
- Task SetSearchTitleAsync(string title);
+ ValueTask SetSearchTitleAsync(string title);
- Task OnDefinitionFoundAsync(DefinitionItem definition);
- Task OnReferenceFoundAsync(SourceReferenceItem reference);
+ ValueTask OnDefinitionFoundAsync(DefinitionItem definition);
+ ValueTask OnReferenceFoundAsync(SourceReferenceItem reference);
[Obsolete("Use ProgressTracker instead", error: false)]
- Task ReportProgressAsync(int current, int maximum);
+ ValueTask ReportProgressAsync(int current, int maximum);
}
}
diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs
new file mode 100644
index 0000000000000..e155e0ca31437
--- /dev/null
+++ b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs
@@ -0,0 +1,234 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.FindSymbols;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.FindUsages
+{
+ internal interface IRemoteFindUsagesService
+ {
+ internal interface ICallback
+ {
+ ValueTask AddItemsAsync(int count);
+ ValueTask ItemCompletedAsync();
+ ValueTask ReportMessageAsync(string message);
+ ValueTask ReportProgressAsync(int current, int maximum);
+ ValueTask SetSearchTitleAsync(string title);
+ ValueTask OnDefinitionFoundAsync(SerializableDefinitionItem definition);
+ ValueTask OnReferenceFoundAsync(SerializableSourceReferenceItem reference);
+ }
+
+ ValueTask FindReferencesAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectId,
+ FindReferencesSearchOptions options,
+ CancellationToken cancellationToken);
+
+ ValueTask FindImplementationsAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectId,
+ CancellationToken cancellationToken);
+ }
+
+ internal sealed class FindUsagesServerCallback : IRemoteFindUsagesService.ICallback
+ {
+ private readonly Solution _solution;
+ private readonly IFindUsagesContext _context;
+ private readonly Dictionary _idToDefinition = new Dictionary();
+
+ public FindUsagesServerCallback(Solution solution, IFindUsagesContext context)
+ {
+ _solution = solution;
+ _context = context;
+ }
+
+ public ValueTask AddItemsAsync(int count)
+ => _context.ProgressTracker.AddItemsAsync(count);
+
+ public ValueTask ItemCompletedAsync()
+ => _context.ProgressTracker.ItemCompletedAsync();
+
+ public ValueTask ReportMessageAsync(string message)
+ => _context.ReportMessageAsync(message);
+
+ [Obsolete]
+ public ValueTask ReportProgressAsync(int current, int maximum)
+ => _context.ReportProgressAsync(current, maximum);
+
+ public ValueTask SetSearchTitleAsync(string title)
+ => _context.SetSearchTitleAsync(title);
+
+ public ValueTask OnDefinitionFoundAsync(SerializableDefinitionItem definition)
+ {
+ var id = definition.Id;
+ var rehydrated = definition.Rehydrate(_solution);
+
+ lock (_idToDefinition)
+ {
+ _idToDefinition.Add(id, rehydrated);
+ }
+
+ return _context.OnDefinitionFoundAsync(rehydrated);
+ }
+
+ public ValueTask OnReferenceFoundAsync(SerializableSourceReferenceItem reference)
+ => _context.OnReferenceFoundAsync(reference.Rehydrate(_solution, GetDefinition(reference.DefinitionId)));
+
+ private DefinitionItem GetDefinition(int definitionId)
+ {
+ lock (_idToDefinition)
+ {
+ Contract.ThrowIfFalse(_idToDefinition.ContainsKey(definitionId));
+ return _idToDefinition[definitionId];
+ }
+ }
+ }
+
+ [DataContract]
+ internal readonly struct SerializableDocumentSpan
+ {
+ [DataMember(Order = 0)]
+ public readonly DocumentId DocumentId;
+
+ [DataMember(Order = 1)]
+ public readonly TextSpan SourceSpan;
+
+ public SerializableDocumentSpan(DocumentId documentId, TextSpan sourceSpan)
+ {
+ DocumentId = documentId;
+ SourceSpan = sourceSpan;
+ }
+
+ public static SerializableDocumentSpan Dehydrate(DocumentSpan documentSpan)
+ => new(documentSpan.Document.Id, documentSpan.SourceSpan);
+
+ public DocumentSpan Rehydrate(Solution solution)
+ => new(solution.GetDocument(DocumentId), SourceSpan);
+ }
+
+ [DataContract]
+ internal readonly struct SerializableDefinitionItem
+ {
+ [DataMember(Order = 0)]
+ public readonly int Id;
+
+ [DataMember(Order = 1)]
+ public readonly ImmutableArray Tags;
+
+ [DataMember(Order = 2)]
+ public readonly ImmutableArray DisplayParts;
+
+ [DataMember(Order = 3)]
+ public readonly ImmutableArray NameDisplayParts;
+
+ [DataMember(Order = 4)]
+ public readonly ImmutableArray OriginationParts;
+
+ [DataMember(Order = 5)]
+ public readonly ImmutableArray SourceSpans;
+
+ [DataMember(Order = 6)]
+ public readonly ImmutableDictionary Properties;
+
+ [DataMember(Order = 7)]
+ public readonly ImmutableDictionary DisplayableProperties;
+
+ [DataMember(Order = 8)]
+ public readonly bool DisplayIfNoReferences;
+
+ public SerializableDefinitionItem(
+ int id,
+ ImmutableArray tags,
+ ImmutableArray displayParts,
+ ImmutableArray nameDisplayParts,
+ ImmutableArray originationParts,
+ ImmutableArray sourceSpans,
+ ImmutableDictionary properties,
+ ImmutableDictionary displayableProperties,
+ bool displayIfNoReferences)
+ {
+ Id = id;
+ Tags = tags;
+ DisplayParts = displayParts;
+ NameDisplayParts = nameDisplayParts;
+ OriginationParts = originationParts;
+ SourceSpans = sourceSpans;
+ Properties = properties;
+ DisplayableProperties = displayableProperties;
+ DisplayIfNoReferences = displayIfNoReferences;
+ }
+
+ public static SerializableDefinitionItem Dehydrate(int id, DefinitionItem item)
+ => new(id,
+ item.Tags,
+ item.DisplayParts,
+ item.NameDisplayParts,
+ item.OriginationParts,
+ item.SourceSpans.SelectAsArray(ss => SerializableDocumentSpan.Dehydrate(ss)),
+ item.Properties,
+ item.DisplayableProperties,
+ item.DisplayIfNoReferences);
+
+ public DefinitionItem Rehydrate(Solution solution)
+ => new DefinitionItem.DefaultDefinitionItem(
+ Tags,
+ DisplayParts,
+ NameDisplayParts,
+ OriginationParts,
+ SourceSpans.SelectAsArray(ss => ss.Rehydrate(solution)),
+ Properties,
+ DisplayableProperties,
+ DisplayIfNoReferences);
+ }
+
+ [DataContract]
+ internal readonly struct SerializableSourceReferenceItem
+ {
+ [DataMember(Order = 0)]
+ public readonly int DefinitionId;
+
+ [DataMember(Order = 1)]
+ public readonly SerializableDocumentSpan SourceSpan;
+
+ [DataMember(Order = 2)]
+ public readonly SymbolUsageInfo SymbolUsageInfo;
+
+ [DataMember(Order = 3)]
+ public readonly ImmutableDictionary AdditionalProperties;
+
+ public SerializableSourceReferenceItem(
+ int definitionId,
+ SerializableDocumentSpan sourceSpan,
+ SymbolUsageInfo symbolUsageInfo,
+ ImmutableDictionary additionalProperties)
+ {
+ DefinitionId = definitionId;
+ SourceSpan = sourceSpan;
+ SymbolUsageInfo = symbolUsageInfo;
+ AdditionalProperties = additionalProperties;
+ }
+
+ public static SerializableSourceReferenceItem Dehydrate(int definitionId, SourceReferenceItem item)
+ => new(definitionId,
+ SerializableDocumentSpan.Dehydrate(item.SourceSpan),
+ item.SymbolUsageInfo,
+ item.AdditionalProperties);
+
+ public SourceReferenceItem Rehydrate(Solution solution, DefinitionItem definition)
+ => new(definition,
+ SourceSpan.Rehydrate(solution),
+ SymbolUsageInfo,
+ AdditionalProperties.ToImmutableDictionary(t => t.Key, t => t.Value));
+ }
+}
diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs
index 1e375b2f07cf2..fc93cb930df8b 100644
--- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs
+++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs
@@ -38,15 +38,13 @@ public async Task> SearchDocumentAsync(
{
var solution = document.Project.Solution;
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteNavigateToSearchService.SearchDocumentAsync),
+ var result = await client.TryInvokeAsync>(
solution,
- new object[] { document.Id, searchPattern, kinds.ToArray() },
+ (service, solutionInfo, cancellationToken) => service.SearchDocumentAsync(solutionInfo, document.Id, searchPattern, kinds.ToImmutableArray(), cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return result.SelectAsArray(r => r.Rehydrate(solution));
+ return result.HasValue ? result.Value.SelectAsArray(r => r.Rehydrate(solution)) : ImmutableArray.Empty;
}
return await SearchDocumentInCurrentProcessAsync(
@@ -60,16 +58,14 @@ public async Task> SearchProjectAsync(
if (client != null)
{
var solution = project.Solution;
-
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteNavigateToSearchService.SearchProjectAsync),
+ var priorityDocumentIds = priorityDocuments.SelectAsArray(d => d.Id);
+ var result = await client.TryInvokeAsync>(
solution,
- new object[] { project.Id, priorityDocuments.Select(d => d.Id).ToArray(), searchPattern, kinds.ToArray() },
+ (service, solutionInfo, cancellationToken) => service.SearchProjectAsync(solutionInfo, project.Id, priorityDocumentIds, searchPattern, kinds.ToImmutableArray(), cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return result.SelectAsArray(r => r.Rehydrate(solution));
+ return result.HasValue ? result.Value.SelectAsArray(r => r.Rehydrate(solution)) : ImmutableArray.Empty;
}
return await SearchProjectInCurrentProcessAsync(
diff --git a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs
index 7949a1bb3439c..677c502aa2e95 100644
--- a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs
+++ b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
+#nullable enable
+
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
@@ -11,10 +13,10 @@ namespace Microsoft.CodeAnalysis.NavigateTo
{
internal interface IRemoteNavigateToSearchService
{
- Task> SearchDocumentAsync(
- PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken);
+ ValueTask> SearchDocumentAsync(
+ PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, ImmutableArray kinds, CancellationToken cancellationToken);
- Task> SearchProjectAsync(
- PinnedSolutionInfo solutionInfo, ProjectId projectId, DocumentId[] priorityDocumentIds, string searchPattern, string[] kinds, CancellationToken cancellationToken);
+ ValueTask> SearchProjectAsync(
+ PinnedSolutionInfo solutionInfo, ProjectId projectId, ImmutableArray priorityDocumentIds, string searchPattern, ImmutableArray kinds, CancellationToken cancellationToken);
}
}
diff --git a/src/Features/Core/Portable/Remote/RemoteArguments.cs b/src/Features/Core/Portable/Remote/RemoteArguments.cs
index 75d2aaf12ac58..0cb7df7d1b282 100644
--- a/src/Features/Core/Portable/Remote/RemoteArguments.cs
+++ b/src/Features/Core/Portable/Remote/RemoteArguments.cs
@@ -4,50 +4,83 @@
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.NavigateTo;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Text;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote
{
#region NavigateTo
- internal class SerializableNavigateToSearchResult
+ [DataContract]
+ internal readonly struct SerializableNavigateToSearchResult
{
- public string AdditionalInformation;
+ [DataMember(Order = 0)]
+ public readonly string AdditionalInformation;
- public string Kind;
- public NavigateToMatchKind MatchKind;
- public bool IsCaseSensitive;
- public string Name;
- public IList NameMatchSpans;
- public string SecondarySort;
- public string Summary;
+ [DataMember(Order = 1)]
+ public readonly string Kind;
- public SerializableNavigableItem NavigableItem;
+ [DataMember(Order = 2)]
+ public readonly NavigateToMatchKind MatchKind;
- internal static SerializableNavigateToSearchResult Dehydrate(INavigateToSearchResult result)
+ [DataMember(Order = 3)]
+ public readonly bool IsCaseSensitive;
+
+ [DataMember(Order = 4)]
+ public readonly string Name;
+
+ [DataMember(Order = 5)]
+ public readonly ImmutableArray NameMatchSpans;
+
+ [DataMember(Order = 6)]
+ public readonly string SecondarySort;
+
+ [DataMember(Order = 7)]
+ public readonly string Summary;
+
+ [DataMember(Order = 8)]
+ public readonly SerializableNavigableItem NavigableItem;
+
+ public SerializableNavigateToSearchResult(
+ string additionalInformation,
+ string kind,
+ NavigateToMatchKind matchKind,
+ bool isCaseSensitive,
+ string name,
+ ImmutableArray nameMatchSpans,
+ string secondarySort,
+ string summary,
+ SerializableNavigableItem navigableItem)
{
- return new SerializableNavigateToSearchResult
- {
- AdditionalInformation = result.AdditionalInformation,
- Kind = result.Kind,
- MatchKind = result.MatchKind,
- IsCaseSensitive = result.IsCaseSensitive,
- Name = result.Name,
- NameMatchSpans = result.NameMatchSpans,
- SecondarySort = result.SecondarySort,
- Summary = result.Summary,
- NavigableItem = SerializableNavigableItem.Dehydrate(result.NavigableItem)
- };
+ AdditionalInformation = additionalInformation;
+ Kind = kind;
+ MatchKind = matchKind;
+ IsCaseSensitive = isCaseSensitive;
+ Name = name;
+ NameMatchSpans = nameMatchSpans;
+ SecondarySort = secondarySort;
+ Summary = summary;
+ NavigableItem = navigableItem;
}
+ internal static SerializableNavigateToSearchResult Dehydrate(INavigateToSearchResult result)
+ => new(result.AdditionalInformation,
+ result.Kind,
+ result.MatchKind,
+ result.IsCaseSensitive,
+ result.Name,
+ result.NameMatchSpans,
+ result.SecondarySort,
+ result.Summary,
+ SerializableNavigableItem.Dehydrate(result.NavigableItem));
+
internal INavigateToSearchResult Rehydrate(Solution solution)
{
return new NavigateToSearchResult(
AdditionalInformation, Kind, MatchKind, IsCaseSensitive,
- Name, NameMatchSpans.ToImmutableArrayOrEmpty(),
+ Name, NameMatchSpans,
SecondarySort, Summary, NavigableItem.Rehydrate(solution));
}
@@ -82,42 +115,68 @@ public NavigateToSearchResult(
}
}
- internal class SerializableNavigableItem
+ ///
+ /// Note: this is intentionally a class, not struct, to avoid hitting .NET Framework loader bug
+ /// that fails to load a struct S declaring a field of type ImmutableArray of S.
+ ///
+ [DataContract]
+ internal sealed class SerializableNavigableItem
{
- public Glyph Glyph;
+ [DataMember(Order = 0)]
+ public readonly Glyph Glyph;
- public IList DisplayTaggedParts;
+ [DataMember(Order = 1)]
+ public readonly ImmutableArray DisplayTaggedParts;
- public bool DisplayFileLocation;
+ [DataMember(Order = 2)]
+ public readonly bool DisplayFileLocation;
- public bool IsImplicitlyDeclared;
+ [DataMember(Order = 3)]
+ public readonly bool IsImplicitlyDeclared;
- public DocumentId Document;
- public TextSpan SourceSpan;
+ [DataMember(Order = 4)]
+ public readonly DocumentId Document;
- public IList ChildItems;
+ [DataMember(Order = 5)]
+ public readonly TextSpan SourceSpan;
- public static SerializableNavigableItem Dehydrate(INavigableItem item)
+ [DataMember(Order = 6)]
+ public readonly ImmutableArray ChildItems;
+
+ public SerializableNavigableItem(
+ Glyph glyph,
+ ImmutableArray displayTaggedParts,
+ bool displayFileLocation,
+ bool isImplicitlyDeclared,
+ DocumentId document,
+ TextSpan sourceSpan,
+ ImmutableArray childItems)
{
- return new SerializableNavigableItem
- {
- Glyph = item.Glyph,
- DisplayTaggedParts = item.DisplayTaggedParts,
- DisplayFileLocation = item.DisplayFileLocation,
- IsImplicitlyDeclared = item.IsImplicitlyDeclared,
- Document = item.Document.Id,
- SourceSpan = item.SourceSpan,
- ChildItems = item.ChildItems.SelectAsArray(Dehydrate)
- };
+ Glyph = glyph;
+ DisplayTaggedParts = displayTaggedParts;
+ DisplayFileLocation = displayFileLocation;
+ IsImplicitlyDeclared = isImplicitlyDeclared;
+ Document = document;
+ SourceSpan = sourceSpan;
+ ChildItems = childItems;
}
+ public static SerializableNavigableItem Dehydrate(INavigableItem item)
+ => new(item.Glyph,
+ item.DisplayTaggedParts,
+ item.DisplayFileLocation,
+ item.IsImplicitlyDeclared,
+ item.Document.Id,
+ item.SourceSpan,
+ item.ChildItems.SelectAsArray(Dehydrate));
+
public INavigableItem Rehydrate(Solution solution)
{
var childItems = ChildItems == null
? ImmutableArray.Empty
: ChildItems.SelectAsArray(c => c.Rehydrate(solution));
return new NavigableItem(
- Glyph, DisplayTaggedParts.ToImmutableArrayOrEmpty(),
+ Glyph, DisplayTaggedParts,
DisplayFileLocation, IsImplicitlyDeclared,
solution.GetDocument(Document),
SourceSpan,
diff --git a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs
index 029b47ac1cced..d552edcc199f0 100644
--- a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs
+++ b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs
@@ -43,18 +43,16 @@ private TodoCommentData CreateSerializableData(
var originalLineInfo = location.GetLineSpan();
var mappedLineInfo = location.GetMappedLineSpan();
- return new TodoCommentData
- {
- Priority = Descriptor.Priority,
- Message = Message,
- DocumentId = document.Id,
- OriginalLine = originalLineInfo.StartLinePosition.Line,
- OriginalColumn = originalLineInfo.StartLinePosition.Character,
- OriginalFilePath = document.FilePath,
- MappedLine = mappedLineInfo.StartLinePosition.Line,
- MappedColumn = mappedLineInfo.StartLinePosition.Character,
- MappedFilePath = mappedLineInfo.GetMappedFilePathIfExist(),
- };
+ return new(
+ priority: Descriptor.Priority,
+ message: Message,
+ documentId: document.Id,
+ originalLine: originalLineInfo.StartLinePosition.Line,
+ originalColumn: originalLineInfo.StartLinePosition.Character,
+ originalFilePath: document.FilePath,
+ mappedLine: mappedLineInfo.StartLinePosition.Line,
+ mappedColumn: mappedLineInfo.StartLinePosition.Character,
+ mappedFilePath: mappedLineInfo.GetMappedFilePathIfExist());
}
public static async Task ConvertAsync(
diff --git a/src/Features/LanguageServer/Protocol/CustomProtocol/FindUsagesLSPContext.cs b/src/Features/LanguageServer/Protocol/CustomProtocol/FindUsagesLSPContext.cs
index 81d91ee02a4b0..22885baf0515c 100644
--- a/src/Features/LanguageServer/Protocol/CustomProtocol/FindUsagesLSPContext.cs
+++ b/src/Features/LanguageServer/Protocol/CustomProtocol/FindUsagesLSPContext.cs
@@ -75,9 +75,10 @@ public FindUsagesLSPContext(
}
// After all definitions/references have been found, wait here until all results have been reported.
- public override Task OnCompletedAsync() => _workQueue.WaitUntilCurrentBatchCompletesAsync();
+ public override async ValueTask OnCompletedAsync()
+ => await _workQueue.WaitUntilCurrentBatchCompletesAsync().ConfigureAwait(false);
- public override async Task OnDefinitionFoundAsync(DefinitionItem definition)
+ public override async ValueTask OnDefinitionFoundAsync(DefinitionItem definition)
{
using (await _semaphore.DisposableWaitAsync(CancellationToken).ConfigureAwait(false))
{
@@ -112,7 +113,7 @@ public override async Task OnDefinitionFoundAsync(DefinitionItem definition)
}
}
- public override async Task OnReferenceFoundAsync(SourceReferenceItem reference)
+ public override async ValueTask OnReferenceFoundAsync(SourceReferenceItem reference)
{
using (await _semaphore.DisposableWaitAsync(CancellationToken).ConfigureAwait(false))
{
diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs
index de035c19b9e82..319091d2d981d 100644
--- a/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs
+++ b/src/Tools/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs
@@ -22,29 +22,29 @@ public FSharpFindUsagesContext(IFindUsagesContext context)
public Task OnDefinitionFoundAsync(FSharp.FindUsages.FSharpDefinitionItem definition)
{
- return _context.OnDefinitionFoundAsync(definition.RoslynDefinitionItem);
+ return _context.OnDefinitionFoundAsync(definition.RoslynDefinitionItem).AsTask();
}
public Task OnReferenceFoundAsync(FSharp.FindUsages.FSharpSourceReferenceItem reference)
{
- return _context.OnReferenceFoundAsync(reference.RoslynSourceReferenceItem);
+ return _context.OnReferenceFoundAsync(reference.RoslynSourceReferenceItem).AsTask();
}
public Task ReportMessageAsync(string message)
{
- return _context.ReportMessageAsync(message);
+ return _context.ReportMessageAsync(message).AsTask();
}
public Task ReportProgressAsync(int current, int maximum)
{
#pragma warning disable CS0618 // Type or member is obsolete
- return _context.ReportProgressAsync(current, maximum);
+ return _context.ReportProgressAsync(current, maximum).AsTask();
#pragma warning restore CS0618 // Type or member is obsolete
}
public Task SetSearchTitleAsync(string title)
{
- return _context.SetSearchTitleAsync(title);
+ return _context.SetSearchTitleAsync(title).AsTask();
}
}
}
diff --git a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs
index 00b358711f65c..dfa0c1a116312 100644
--- a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs
+++ b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs
@@ -199,16 +199,19 @@ public void Dispose()
// we always get data through VS rather than Roslyn OOP directly since we want final data rather than
// raw data from Roslyn OOP such as razor find all reference results
- var referenceCount = await _callbackService.InvokeAsync(
+ var referenceCountOpt = await _callbackService.InvokeAsync(
_owner,
nameof(ICodeLensContext.GetReferenceCountAsync),
new object[] { Descriptor, descriptorContext },
cancellationToken).ConfigureAwait(false);
- if (referenceCount == null)
+
+ if (!referenceCountOpt.HasValue)
{
return null;
}
+ var referenceCount = referenceCountOpt.Value;
+
var referenceCountString = $"{referenceCount.Count}{(referenceCount.IsCapped ? "+" : string.Empty)}";
return new CodeLensDataPointDescriptor()
{
@@ -220,7 +223,7 @@ public void Dispose()
ImageId = null
};
- string GetCodeElementKindsString(CodeElementKinds kind)
+ static string GetCodeElementKindsString(CodeElementKinds kind)
{
switch (kind)
{
@@ -242,53 +245,53 @@ public async Task GetDetailsAsync(CodeLensDescriptorC
{
// we always get data through VS rather than Roslyn OOP directly since we want final data rather than
// raw data from Roslyn OOP such as razor find all reference results
- var referenceLocationDescriptors = await _callbackService.InvokeAsync>(
+ var referenceLocationDescriptors = await _callbackService.InvokeAsync?>(
_owner,
nameof(ICodeLensContext.FindReferenceLocationsAsync),
new object[] { Descriptor, descriptorContext },
cancellationToken).ConfigureAwait(false);
- var details = new CodeLensDetailsDescriptor
+ var entries = referenceLocationDescriptors?.Select(referenceLocationDescriptor =>
{
- Headers = s_header,
- Entries = referenceLocationDescriptors.Select(referenceLocationDescriptor =>
+ ImageId imageId = default;
+ if (referenceLocationDescriptor.Glyph.HasValue)
{
- ImageId imageId = default;
- if (referenceLocationDescriptor.Glyph.HasValue)
- {
- var moniker = referenceLocationDescriptor.Glyph.Value.GetImageMoniker();
- imageId = new ImageId(moniker.Guid, moniker.Id);
- }
+ var moniker = referenceLocationDescriptor.Glyph.Value.GetImageMoniker();
+ imageId = new ImageId(moniker.Guid, moniker.Id);
+ }
- return new CodeLensDetailEntryDescriptor()
+ return new CodeLensDetailEntryDescriptor()
+ {
+ // use default since reference codelens don't require special behaviors
+ NavigationCommand = null,
+ NavigationCommandArgs = null,
+ Tooltip = null,
+ Fields = new List()
{
- // use default since reference codelens don't require special behaviors
- NavigationCommand = null,
- NavigationCommandArgs = null,
- Tooltip = null,
- Fields = new List()
- {
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.FilePath },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.LineNumber.ToString() },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ColumnNumber.ToString() },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ReferenceLineText },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ReferenceStart.ToString() },
- new CodeLensDetailEntryField() { Text = (referenceLocationDescriptor.ReferenceStart + referenceLocationDescriptor.ReferenceLength).ToString() },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.LongDescription },
- new CodeLensDetailEntryField() { ImageId = imageId },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.BeforeReferenceText2 },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.BeforeReferenceText1 },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.AfterReferenceText1 },
- new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.AfterReferenceText2 }
- },
- };
- }).ToList(),
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.FilePath },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.LineNumber.ToString() },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ColumnNumber.ToString() },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ReferenceLineText },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.ReferenceStart.ToString() },
+ new CodeLensDetailEntryField() { Text = (referenceLocationDescriptor.ReferenceStart + referenceLocationDescriptor.ReferenceLength).ToString() },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.LongDescription },
+ new CodeLensDetailEntryField() { ImageId = imageId },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.BeforeReferenceText2 },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.BeforeReferenceText1 },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.AfterReferenceText1 },
+ new CodeLensDetailEntryField() { Text = referenceLocationDescriptor.AfterReferenceText2 }
+ },
+ };
+ }).ToList();
+
+ return new CodeLensDetailsDescriptor
+ {
+ Headers = s_header,
+ Entries = entries ?? SpecializedCollections.EmptyList(),
// use default behavior
PaneNavigationCommands = null
};
-
- return details;
}
internal void Invalidate()
diff --git a/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs b/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs
index f0c322dd8f3ba..4c94b7606eaa6 100644
--- a/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs
+++ b/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -25,18 +26,18 @@ internal class UnitTestingReferencesService
CodeLensDescriptorContext descriptorContext,
CancellationToken cancellationToken)
{
- var callerMethods = await callbackService.InvokeAsync>(
+ var callerMethods = await callbackService.InvokeAsync?>(
provider,
nameof(ICodeLensContext.FindReferenceMethodsAsync),
new object[] { descriptor, descriptorContext },
cancellationToken).ConfigureAwait(false);
- if (callerMethods == null || !callerMethods.Any())
+ if (!callerMethods.HasValue || callerMethods.Value.IsEmpty)
{
return Empty;
}
- return callerMethods.Select(m => (
+ return callerMethods.Value.SelectAsArray(m => (
MethodFullyQualifiedName: m.FullName,
MethodFilePath: m.FilePath,
MethodOutputFilePath: m.OutputFilePath));
diff --git a/src/VisualStudio/Core/Def/Implementation/CodeLens/CodeLensCallbackListener.cs b/src/VisualStudio/Core/Def/Implementation/CodeLens/CodeLensCallbackListener.cs
index f1fac962d790f..b7eb9660005be 100644
--- a/src/VisualStudio/Core/Def/Implementation/CodeLens/CodeLensCallbackListener.cs
+++ b/src/VisualStudio/Core/Def/Implementation/CodeLens/CodeLensCallbackListener.cs
@@ -93,7 +93,7 @@ public async Task> GetProjectVersionsAsync(Imm
return await service.GetReferenceCountAsync(solution, documentId, node, maxSearchResults, cancellationToken).ConfigureAwait(false);
}
- public async Task?> FindReferenceLocationsAsync(
+ public async Task?> FindReferenceLocationsAsync(
CodeLensDescriptor descriptor, CodeLensDescriptorContext descriptorContext, CancellationToken cancellationToken)
{
var solution = _workspace.CurrentSolution;
@@ -108,7 +108,7 @@ public async Task> GetProjectVersionsAsync(Imm
return await service.FindReferenceLocationsAsync(solution, documentId, node, cancellationToken).ConfigureAwait(false);
}
- public async Task?> FindReferenceMethodsAsync(
+ public async Task?> FindReferenceMethodsAsync(
CodeLensDescriptor descriptor, CodeLensDescriptorContext descriptorContext, CancellationToken cancellationToken)
{
var solution = _workspace.CurrentSolution;
diff --git a/src/VisualStudio/Core/Def/Implementation/CodeLens/ICodeLensContext.cs b/src/VisualStudio/Core/Def/Implementation/CodeLens/ICodeLensContext.cs
index afd05c09fc019..553d7beceed41 100644
--- a/src/VisualStudio/Core/Def/Implementation/CodeLens/ICodeLensContext.cs
+++ b/src/VisualStudio/Core/Def/Implementation/CodeLens/ICodeLensContext.cs
@@ -31,13 +31,13 @@ internal interface ICodeLensContext
///
/// get reference location descriptor of the given descriptor
///
- Task?> FindReferenceLocationsAsync(
+ Task?> FindReferenceLocationsAsync(
CodeLensDescriptor descriptor, CodeLensDescriptorContext descriptorContext, CancellationToken cancellationToken);
///
/// Given a document and syntax node, returns a collection of locations of methods that refer to the located node.
///
- Task?> FindReferenceMethodsAsync(
+ Task?> FindReferenceMethodsAsync(
CodeLensDescriptor descriptor, CodeLensDescriptorContext descriptorContext, CancellationToken cancellationToken);
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs b/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs
index 87558a9ea8021..faa2c4bb96bf1 100644
--- a/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs
@@ -2,7 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
@@ -12,6 +15,7 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
+using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
@@ -27,7 +31,7 @@ public RemoteCodeLensReferencesService()
{
}
- public async Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, int maxSearchResults,
+ public async Task GetReferenceCountAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode, int maxSearchResults,
CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.CodeLens_GetReferenceCountAsync, cancellationToken))
@@ -40,36 +44,41 @@ public async Task GetReferenceCountAsync(Solution solution, Docu
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- return await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteCodeLensReferencesService.GetReferenceCountAsync),
+ var result = await client.TryInvokeAsync(
solution,
- new object[] { documentId, syntaxNode.Span, maxSearchResults },
+ (service, solutionInfo, cancellationToken) => service.GetReferenceCountAsync(solutionInfo, documentId, syntaxNode.Span, maxSearchResults, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+
+ return result.HasValue ? result.Value : null;
}
return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync(solution, documentId, syntaxNode, maxSearchResults, cancellationToken).ConfigureAwait(false);
}
}
- public async Task> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
+ public async Task?> FindReferenceLocationsAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode,
CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.CodeLens_FindReferenceLocationsAsync, cancellationToken))
{
+ if (syntaxNode == null)
+ {
+ return null;
+ }
+
var descriptors = await FindReferenceLocationsWorkerAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
- if (descriptors == null)
+ if (!descriptors.HasValue)
{
return null;
}
// map spans to right locations using SpanMapper for documents such as cshtml and etc
- return await FixUpDescriptorsAsync(solution, descriptors, cancellationToken).ConfigureAwait(false);
+ return await FixUpDescriptorsAsync(solution, descriptors.Value, cancellationToken).ConfigureAwait(false);
}
}
- public async Task> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
+ public async Task?> FindReferenceMethodsAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode,
CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.CodeLens_FindReferenceMethodsAsync, cancellationToken))
@@ -82,20 +91,20 @@ public async Task> FindReferenceMethodsAs
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- return await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteCodeLensReferencesService.FindReferenceMethodsAsync),
+ var result = await client.TryInvokeAsync?>(
solution,
- new object[] { documentId, syntaxNode.Span },
+ (service, solutionInfo, cancellationToken) => service.FindReferenceMethodsAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+
+ return result.HasValue ? result.Value : null;
}
return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
}
- public async Task GetFullyQualifiedNameAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
+ public async Task GetFullyQualifiedNameAsync(Solution solution, DocumentId documentId, SyntaxNode? syntaxNode,
CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.CodeLens_GetFullyQualifiedName, cancellationToken))
@@ -108,31 +117,35 @@ public async Task GetFullyQualifiedNameAsync(Solution solution, Document
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- return await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteCodeLensReferencesService.GetFullyQualifiedNameAsync),
+ var result = await client.TryInvokeAsync(
solution,
- new object[] { documentId, syntaxNode.Span },
+ (service, solutionInfo, cancellationToken) => service.GetFullyQualifiedNameAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+
+ return result.HasValue ? result.Value : null;
}
return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedNameAsync(solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false);
}
}
- private static async Task> FixUpDescriptorsAsync(
- Solution solution, IEnumerable descriptors, CancellationToken cancellationToken)
+ private static async Task> FixUpDescriptorsAsync(
+ Solution solution, ImmutableArray descriptors, CancellationToken cancellationToken)
{
- var list = new List();
+ using var _ = ArrayBuilder.GetInstance(out var list);
foreach (var descriptor in descriptors)
{
var referencedDocumentId = DocumentId.CreateFromSerialized(
ProjectId.CreateFromSerialized(descriptor.ProjectGuid), descriptor.DocumentGuid);
var document = solution.GetDocument(referencedDocumentId);
+ if (document == null)
+ {
+ continue;
+ }
- var spanMapper = document?.Services.GetService();
+ var spanMapper = document.Services.GetService();
if (spanMapper == null)
{
// for normal document, just add one as they are
@@ -182,7 +195,7 @@ private static async Task> FixUpDescrip
after2));
}
- return list;
+ return list.ToImmutable();
}
private static (string text, int start, int length) GetReferenceInfo(ExcerptResult? reference, ReferenceLocationDescriptor descriptor)
@@ -226,24 +239,24 @@ private static string GetLineTextOrEmpty(TextLineCollection lines, int index)
return lines[index].ToString().TrimEnd();
}
- private async Task> FindReferenceLocationsWorkerAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
+ private static async Task?> FindReferenceLocationsWorkerAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
if (syntaxNode == null)
{
- return null;
+ return ImmutableArray.Empty;
}
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- return await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteCodeLensReferencesService.FindReferenceLocationsAsync),
+ var result = await client.TryInvokeAsync?>(
solution,
- new object[] { documentId, syntaxNode.Span },
+ (service, solutionInfo, cancellationToken) => service.FindReferenceLocationsAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
+
+ return result.HasValue ? result.Value : null;
}
// remote host is not running. this can happen if remote host is disabled.
diff --git a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
index d3b36d99eb96c..b00ce35c3a9a5 100644
--- a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs
@@ -44,7 +44,7 @@ internal class VisualStudioDesignerAttributeService
/// Our connection to the remote OOP server. Created on demand when we startup and then
/// kept around for the lifetime of this service.
///
- private RemoteServiceConnection? _lazyConnection;
+ private RemoteServiceConnection? _lazyConnection;
///
/// Cache from project to the CPS designer service for it. Computed on demand (which
@@ -123,7 +123,7 @@ private async Task StartWorkerAsync()
// Pass ourselves in as the callback target for the OOP service. As it discovers
// designer attributes it will call back into us to notify VS about it.
- _lazyConnection = await client.CreateConnectionAsync(callbackTarget: this, cancellationToken).ConfigureAwait(false);
+ _lazyConnection = await client.CreateConnectionAsync(callbackTarget: this, cancellationToken).ConfigureAwait(false);
// Now kick off scanning in the OOP process.
// If the call fails an error has already been reported and there is nothing more to do.
diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
index 1929d1521c11c..e0fc7532e2b41 100644
--- a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
+++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
@@ -276,14 +276,14 @@ public IDisposable Subscribe(ITableDataSink sink)
#region FindUsagesContext overrides.
- public sealed override Task SetSearchTitleAsync(string title)
+ public sealed override ValueTask SetSearchTitleAsync(string title)
{
// Note: IFindAllReferenceWindow.Title is safe to set from any thread.
_findReferencesWindow.Title = title;
- return Task.CompletedTask;
+ return default;
}
- public sealed override async Task OnCompletedAsync()
+ public sealed override async ValueTask OnCompletedAsync()
{
await OnCompletedAsyncWorkerAsync().ConfigureAwait(false);
@@ -292,7 +292,7 @@ public sealed override async Task OnCompletedAsync()
protected abstract Task OnCompletedAsyncWorkerAsync();
- public sealed override Task OnDefinitionFoundAsync(DefinitionItem definition)
+ public sealed override ValueTask OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (Gate)
{
@@ -302,7 +302,7 @@ public sealed override Task OnDefinitionFoundAsync(DefinitionItem definition)
return OnDefinitionFoundWorkerAsync(definition);
}
- protected abstract Task OnDefinitionFoundWorkerAsync(DefinitionItem definition);
+ protected abstract ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem definition);
protected async Task<(Guid, string projectName, SourceText)> GetGuidAndProjectNameAndSourceTextAsync(Document document)
{
@@ -369,10 +369,10 @@ protected async Task TryCreateDocumentSpanEntryAsync(
return (excerptResult, AbstractDocumentSpanEntry.GetLineContainingPosition(sourceText, documentSpan.SourceSpan.Start));
}
- public sealed override Task OnReferenceFoundAsync(SourceReferenceItem reference)
+ public sealed override ValueTask OnReferenceFoundAsync(SourceReferenceItem reference)
=> OnReferenceFoundWorkerAsync(reference);
- protected abstract Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference);
+ protected abstract ValueTask OnReferenceFoundWorkerAsync(SourceReferenceItem reference);
protected RoslynDefinitionBucket GetOrCreateDefinitionBucket(DefinitionItem definition)
{
@@ -388,13 +388,13 @@ protected RoslynDefinitionBucket GetOrCreateDefinitionBucket(DefinitionItem defi
}
}
- public sealed override Task ReportMessageAsync(string message)
+ public sealed override ValueTask ReportMessageAsync(string message)
=> throw new InvalidOperationException("This should never be called in the streaming case.");
- protected sealed override Task ReportProgressAsync(int current, int maximum)
+ protected sealed override ValueTask ReportProgressAsync(int current, int maximum)
{
_progressQueue.AddWork((current, maximum));
- return Task.CompletedTask;
+ return default;
}
private Task UpdateTableProgressAsync(ImmutableArray<(int current, int maximum)> nextBatch, CancellationToken cancellationToken)
diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithReferencesFindUsagesContext.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithReferencesFindUsagesContext.cs
index a0725532785e3..afee03db1277b 100644
--- a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithReferencesFindUsagesContext.cs
+++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithReferencesFindUsagesContext.cs
@@ -37,7 +37,7 @@ public WithReferencesFindUsagesContext(
{
}
- protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
+ protected override async ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem definition)
{
// If this is a definition we always want to show, then create entries
// for all the declaration locations immediately. Otherwise, we'll
@@ -103,7 +103,7 @@ private bool HasDeclarationEntries(DefinitionItem definition)
}
}
- protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
+ protected override ValueTask OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
{
// Normal references go into both sets of entries. We ensure an entry for the definition, and an entry
// for the reference itself.
@@ -118,7 +118,7 @@ protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem referenc
addToEntriesWhenNotGroupingByDefinition: true);
}
- protected async Task OnEntryFoundAsync(
+ protected async ValueTask OnEntryFoundAsync(
DefinitionItem definition,
Func> createEntryAsync,
bool addToEntriesWhenGroupingByDefinition,
diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs
index 0918cc8b6fab5..00689589c8480 100644
--- a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs
+++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs
@@ -34,14 +34,14 @@ public WithoutReferencesFindUsagesContext(
}
// We should never be called in a context where we get references.
- protected override Task OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
+ protected override ValueTask OnReferenceFoundWorkerAsync(SourceReferenceItem reference)
=> throw new InvalidOperationException();
// Nothing to do on completion.
protected override Task OnCompletedAsyncWorkerAsync()
=> Task.CompletedTask;
- protected override async Task OnDefinitionFoundWorkerAsync(DefinitionItem definition)
+ protected override async ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem definition)
{
var definitionBucket = GetOrCreateDefinitionBucket(definition);
diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
index cfec1aaf6663d..895aeec7bc1c8 100644
--- a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs
@@ -49,7 +49,7 @@ private readonly ConcurrentDictionary
- private RemoteServiceConnection? _lazyConnection;
+ private RemoteServiceConnection? _lazyConnection;
///
/// Queue where we enqueue the information we get from OOP to process in batch in the future.
@@ -120,7 +120,7 @@ private async Task StartWorkerAsync()
// Pass ourselves in as the callback target for the OOP service. As it discovers
// todo comments it will call back into us to notify VS about it.
- _lazyConnection = await client.CreateConnectionAsync(callbackTarget: this, cancellationToken).ConfigureAwait(false);
+ _lazyConnection = await client.CreateConnectionAsync(callbackTarget: this, cancellationToken).ConfigureAwait(false);
// Now that we've started, let the VS todo list know to start listening to us
_eventListenerTracker.EnsureEventListener(_workspace, this);
diff --git a/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs b/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs
index d6c7e06cbd236..e51c5e7179a6c 100644
--- a/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs
@@ -208,7 +208,8 @@ private static List CollectServiceHubLogFilePaths()
// name our services more consistently to simplify filtering
// filter logs that are not relevant to Roslyn investigation
- if (!name.Contains("-" + RemoteServiceName.Prefix) &&
+ if (!name.Contains("-" + ServiceDescriptors.ServiceNamePrefix) &&
+ !name.Contains("-" + RemoteServiceName.Prefix) &&
!name.Contains("-" + RemoteServiceName.IntelliCodeServiceName) &&
!name.Contains("-" + RemoteServiceName.RazorServiceName) &&
!name.Contains("-" + RemoteServiceName.UnitTestingAnalysisServiceName) &&
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.ExceptionFormatting.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.ExceptionFormatting.cs
index 1b7ca6d514888..ce225d3fb2b73 100644
--- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.ExceptionFormatting.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.ExceptionFormatting.cs
@@ -21,26 +21,14 @@ private static string GetFormattedExceptionStack(Exception exception)
return GetStackForAggregateException(exception, aggregate);
}
- if (exception is RemoteInvocationException remoteException)
+ if (exception is RemoteInvocationException)
{
- return GetStackForRemoteException(remoteException);
+ return exception.ToString();
}
return GetStackForException(exception, includeMessageOnly: false);
}
- private static string GetStackForRemoteException(RemoteInvocationException remoteException)
- {
- var text = GetStackForException(remoteException, includeMessageOnly: true);
- if (remoteException.ErrorData == null)
- {
- return text;
- }
-
- text = $"{text}{Environment.NewLine}---> (Remote Exception) {remoteException.ErrorData.ToString()} <--- {Environment.NewLine}";
- return text;
- }
-
private static string GetStackForAggregateException(Exception exception, AggregateException aggregate)
{
var text = GetStackForException(exception, includeMessageOnly: true);
@@ -95,7 +83,7 @@ private static string GetAsyncStackTrace(Exception exception)
where ShouldShowFrame(declaringType)
select FormatFrame(method, declaringType);
var stringBuilder = new StringBuilder();
- return String.Join(Environment.NewLine, stackFrameLines);
+ return string.Join(Environment.NewLine, stackFrameLines);
}
private static bool ShouldShowFrame(Type declaringType) =>
@@ -120,7 +108,7 @@ private static string FormatFrame(MethodBase method, Type declaringType)
FormatGenericArguments(stringBuilder, declaringType.GetGenericArguments());
}
- stringBuilder.Append("(");
+ stringBuilder.Append('(');
if (isAsync)
{
stringBuilder.Append(ServicesVSResources.Unknown_parameters);
@@ -130,7 +118,7 @@ private static string FormatFrame(MethodBase method, Type declaringType)
FormatParameters(stringBuilder, method);
}
- stringBuilder.Append(")");
+ stringBuilder.Append(')');
return stringBuilder.ToString();
}
@@ -174,7 +162,7 @@ private static void FormatGenericArguments(StringBuilder stringBuilder, Type[] g
return;
}
- stringBuilder.Append("[" + String.Join(",", genericTypeArguments.Select(args => args.Name)) + "]");
+ stringBuilder.Append("[" + string.Join(",", genericTypeArguments.Select(args => args.Name)) + "]");
}
private static void FormatParameters(StringBuilder stringBuilder, MethodBase method) =>
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.cs
index 6d28cc1735082..96868c61c0aed 100644
--- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioErrorReportingService.cs
@@ -21,6 +21,8 @@ internal partial class VisualStudioErrorReportingService : IErrorReportingServic
public VisualStudioErrorReportingService(IInfoBarService infoBarService)
=> _infoBarService = infoBarService;
+ public string HostDisplayName => "Visual Studio";
+
public void ShowErrorInfoInActiveView(string message, params InfoBarUI[] items)
=> _infoBarService.ShowInfoBarInActiveView(message, items);
@@ -33,6 +35,8 @@ public void ShowDetailedErrorInfo(Exception exception)
new DetailedErrorInfoDialog(exception.Message, errorInfo).ShowModal();
}
+ // obsolete - will remove once we remove JsonRpcConnection
+ // https://github.com/dotnet/roslyn/issues/45859
public void ShowRemoteHostCrashedErrorInfo(Exception? exception)
{
if (s_infoBarReported)
@@ -64,5 +68,21 @@ public void ShowRemoteHostCrashedErrorInfo(Exception? exception)
ServicesVSResources.Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio,
infoBarUIs.ToArray());
}
+
+ public void ShowFeatureNotAvailableErrorInfo(string message, Exception? exception)
+ {
+ var infoBarUIs = new List();
+
+ if (exception != null)
+ {
+ infoBarUIs.Add(new InfoBarUI(
+ WorkspacesResources.Show_Stack_Trace,
+ InfoBarUI.UIKind.HyperLink,
+ () => ShowDetailedErrorInfo(exception),
+ closeAfterAction: true));
+ }
+
+ ShowGlobalErrorInfo(message, infoBarUIs.ToArray());
+ }
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioRemoteHostClientShutdownCancellationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioRemoteHostClientShutdownCancellationService.cs
new file mode 100644
index 0000000000000..0bf150f5dfaad
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioRemoteHostClientShutdownCancellationService.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System;
+using System.Composition;
+using System.Threading;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.VisualStudio.Shell;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation
+{
+ [ExportWorkspaceService(typeof(IRemoteHostClientShutdownCancellationService), ServiceLayer.Host), Shared]
+ internal sealed class VisualStudioRemoteHostClientShutdownCancellationService : IRemoteHostClientShutdownCancellationService
+ {
+ [ImportingConstructor]
+ [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ public VisualStudioRemoteHostClientShutdownCancellationService()
+ {
+ }
+
+ public CancellationToken ShutdownToken => VsShellUtilities.ShutdownToken;
+ }
+}
diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs
index d5583833880c3..8a6be3647de88 100644
--- a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs
+++ b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs
@@ -8,7 +8,6 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.VisualStudio.Shell.Interop;
-using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
{
@@ -26,23 +25,23 @@ public LogService(IThreadingContext threadingContext, IVsActivityLog activityLog
_activityLog = activityLog;
}
- public Task LogInfoAsync(string text)
+ public ValueTask LogInfoAsync(string text, CancellationToken cancellationToken)
=> LogAsync(text, __ACTIVITYLOG_ENTRYTYPE.ALE_INFORMATION);
- public Task LogExceptionAsync(string exception, string text)
+ public ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken)
=> LogAsync(text + ". " + exception, __ACTIVITYLOG_ENTRYTYPE.ALE_ERROR);
- private Task LogAsync(string text, __ACTIVITYLOG_ENTRYTYPE type)
+ private ValueTask LogAsync(string text, __ACTIVITYLOG_ENTRYTYPE type)
{
Log(text, type);
- return Task.CompletedTask;
+ return default;
}
private void Log(string text, __ACTIVITYLOG_ENTRYTYPE type)
{
- if (!this.IsForeground())
+ if (!IsForeground())
{
- this.InvokeBelowInputPriorityAsync(() => Log(text, type));
+ InvokeBelowInputPriorityAsync(() => Log(text, type));
return;
}
diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs
index 1c0b5be7ac4ef..05295bdd9cd66 100644
--- a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs
+++ b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs
@@ -77,7 +77,7 @@ protected override void StartWorking()
{
// Always pull down the nuget.org index. It contains the MS reference assembly index
// inside of it.
- Task.Run(() => UpdateSourceInBackgroundAsync(SymbolSearchUpdateEngine.NugetOrgSource));
+ Task.Run(() => UpdateSourceInBackgroundAsync(SymbolSearchUpdateEngine.NugetOrgSource, ThreadingContext.DisposalToken));
}
private async Task GetEngineAsync(CancellationToken cancellationToken)
@@ -89,13 +89,13 @@ private async Task GetEngineAsync(CancellationToken c
}
}
- private async Task UpdateSourceInBackgroundAsync(string sourceName)
+ private async Task UpdateSourceInBackgroundAsync(string sourceName, CancellationToken cancellationToken)
{
- var engine = await GetEngineAsync(this.ThreadingContext.DisposalToken).ConfigureAwait(false);
- await engine.UpdateContinuouslyAsync(sourceName, _localSettingsDirectory).ConfigureAwait(false);
+ var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false);
+ await engine.UpdateContinuouslyAsync(sourceName, _localSettingsDirectory, cancellationToken).ConfigureAwait(false);
}
- public async Task> FindPackagesWithTypeAsync(
+ public async ValueTask> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken)
{
var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false);
@@ -105,7 +105,7 @@ public async Task> FindPackagesWithTypeAsync(
return FilterAndOrderPackages(allPackagesWithType);
}
- public async Task> FindPackagesWithAssemblyAsync(
+ public async ValueTask> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken)
{
var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false);
@@ -157,7 +157,7 @@ private ImmutableArray FilterAndOrderPackages(
return result.ToImmutableAndFree();
}
- public async Task> FindReferenceAssembliesWithTypeAsync(
+ public async ValueTask> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken)
{
var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false);
diff --git a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
index a0a8660271e02..cb9cd2ab96322 100644
--- a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
+++ b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
@@ -76,12 +76,10 @@ public async Task TestSessionWithNoSolution()
var mock = new MockLogService();
var client = await service.TryGetRemoteHostClientAsync(CancellationToken.None);
- using var connection = await client.CreateConnectionAsync(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, callbackTarget: mock, CancellationToken.None);
- await connection.RunRemoteAsync(
- nameof(IRemoteSymbolSearchUpdateEngine.UpdateContinuouslyAsync),
- solution: null,
- new object[] { "emptySource", Path.GetTempPath() },
- CancellationToken.None);
+ using var connection = await client.CreateConnectionAsync(callbackTarget: mock, CancellationToken.None);
+ Assert.True(await connection.TryInvokeAsync(
+ (service, cancellationToken) => service.UpdateContinuouslyAsync("emptySource", Path.GetTempPath(), cancellationToken),
+ CancellationToken.None));
}
[Fact]
@@ -152,8 +150,8 @@ public Assembly LoadFromPath(string fullPath)
private class MockLogService : ISymbolSearchLogService
{
- public Task LogExceptionAsync(string exception, string text) => Task.CompletedTask;
- public Task LogInfoAsync(string text) => Task.CompletedTask;
+ public ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken) => default;
+ public ValueTask LogInfoAsync(string text, CancellationToken cancellationToken) => default;
}
}
}
diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
index e2d786272672d..db7c6216f43f7 100644
--- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
+++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
@@ -138,7 +138,7 @@ public async Task TestTodoComments()
var cancellationTokenSource = new CancellationTokenSource();
- using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token);
+ using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token);
var invokeTask = connection.TryInvokeAsync(
(service, cancellationToken) => service.ComputeTodoCommentsAsync(cancellationToken),
@@ -149,18 +149,16 @@ public async Task TestTodoComments()
Assert.Equal(1, data.Item2.Length);
var commentInfo = data.Item2[0];
- Assert.Equal(new TodoCommentData
- {
- DocumentId = solution.Projects.Single().Documents.Single().Id,
- Priority = 1,
- Message = "TODO: Test",
- MappedFilePath = null,
- OriginalFilePath = "test1.cs",
- OriginalLine = 2,
- MappedLine = 2,
- OriginalColumn = 3,
- MappedColumn = 3,
- }, commentInfo);
+ Assert.Equal(new TodoCommentData(
+ documentId: solution.Projects.Single().Documents.Single().Id,
+ priority: 1,
+ message: "TODO: Test",
+ mappedFilePath: null,
+ originalFilePath: "test1.cs",
+ originalLine: 2,
+ mappedLine: 2,
+ originalColumn: 3,
+ mappedColumn: 3), commentInfo);
cancellationTokenSource.Cancel();
@@ -216,7 +214,7 @@ public async Task TestDesignerAttributes()
var callback = new DesignerAttributeListener();
- using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token);
+ using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token);
var invokeTask = connection.TryInvokeAsync(
(service, cancellationToken) => service.StartScanningForDesignerAttributesAsync(cancellationToken),
diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs
index 6fcb0e98f00db..daa81fadf0575 100644
--- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs
+++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs
@@ -98,7 +98,7 @@ End Sub
}
}
- [Fact(Skip = "https://github.com/dotnet/roslyn/issues/47720"), Trait(Traits.Feature, Traits.Features.RemoteHost)]
+ [Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task TestCancellation()
{
var code = @"class Test { void Method() { } }";
diff --git a/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb
index 9a96accafd5eb..382b984035ce4 100644
--- a/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb
+++ b/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb
@@ -236,8 +236,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
Dim snapshot1 = factory.GetCurrentSnapshot()
provider.Items = New TodoCommentData() {
- New TodoCommentData With {.Priority = 1, .Message = "test2", .DocumentId = documentId, .MappedLine = 11, .OriginalLine = 11, .MappedColumn = 21, .OriginalColumn = 21, .MappedFilePath = Nothing, .OriginalFilePath = "test2"},
- New TodoCommentData With {.Priority = 0, .Message = "test", .DocumentId = documentId, .MappedLine = 11, .OriginalLine = 11, .MappedColumn = 21, .OriginalColumn = 21, .MappedFilePath = Nothing, .OriginalFilePath = "test1"}
+ New TodoCommentData(priority:=1, message:="test2", documentId:=documentId, mappedLine:=11, originalLine:=11, mappedColumn:=21, originalColumn:=21, mappedFilePath:=Nothing, originalFilePath:="test2"),
+ New TodoCommentData(priority:=0, message:="test", documentId:=documentId, mappedLine:=11, originalLine:=11, mappedColumn:=21, originalColumn:=21, mappedFilePath:=Nothing, originalFilePath:="test1")
}
provider.RaiseTodoListUpdated(workspace)
@@ -270,8 +270,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
Dim snapshot1 = factory.GetCurrentSnapshot()
provider.Items = New TodoCommentData() {
- New TodoCommentData With {.Priority = 1, .Message = "test2", .DocumentId = documentId, .MappedLine = 11, .OriginalLine = 11, .MappedColumn = 21, .OriginalColumn = 21, .MappedFilePath = Nothing, .OriginalFilePath = "test2"},
- New TodoCommentData With {.Priority = 0, .Message = "test3", .DocumentId = documentId, .MappedLine = 11, .OriginalLine = 11, .MappedColumn = 21, .OriginalColumn = 21, .MappedFilePath = Nothing, .OriginalFilePath = "test3"}
+ New TodoCommentData(priority:=1, message:="test2", documentId:=documentId, mappedLine:=11, originalLine:=11, mappedColumn:=21, originalColumn:=21, mappedFilePath:=Nothing, originalFilePath:="test2"),
+ New TodoCommentData(priority:=0, message:="test3", documentId:=documentId, mappedLine:=11, originalLine:=11, mappedColumn:=21, originalColumn:=21, mappedFilePath:=Nothing, originalFilePath:="test3")
}
provider.RaiseTodoListUpdated(workspace)
@@ -360,17 +360,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
End Sub
Private Function CreateItem(documentId As DocumentId) As TodoCommentData
- Return New TodoCommentData With {
- .Priority = 0,
- .Message = "test",
- .DocumentId = documentId,
- .MappedLine = 10,
- .OriginalLine = 10,
- .MappedColumn = 20,
- .OriginalColumn = 20,
- .MappedFilePath = Nothing,
- .OriginalFilePath = "test1"
- }
+ Return New TodoCommentData(
+ priority:=0,
+ message:="test",
+ documentId:=documentId,
+ mappedLine:=10,
+ originalLine:=10,
+ mappedColumn:=20,
+ originalColumn:=20,
+ mappedFilePath:=Nothing,
+ originalFilePath:="test1")
End Function
Private Class TestTodoListProvider
diff --git a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb
index d5f83e815a2a2..cefc8fe99a6b2 100644
--- a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb
+++ b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb
@@ -744,12 +744,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch
Private Sub New()
End Sub
- Public Function LogExceptionAsync(exception As String, text As String) As Task Implements ISymbolSearchLogService.LogExceptionAsync
- Return Task.CompletedTask
+ Public Function LogExceptionAsync(exception As String, text As String, cancellationToken As CancellationToken) As ValueTask Implements ISymbolSearchLogService.LogExceptionAsync
+ Return Nothing
End Function
- Public Function LogInfoAsync(text As String) As Task Implements ISymbolSearchLogService.LogInfoAsync
- Return Task.CompletedTask
+ Public Function LogInfoAsync(text As String, cancellationToken As CancellationToken) As ValueTask Implements ISymbolSearchLogService.LogInfoAsync
+ Return Nothing
End Function
End Class
End Class
diff --git a/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb b/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb
index c86a1a16434e7..94c321c941ce5 100644
--- a/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb
+++ b/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb
@@ -143,6 +143,7 @@ class {|Definition:C1|}
Dim root = Await startDocument.GetSyntaxRootAsync()
Dim node = root.FindNode(originalDocument.AnnotatedSpans("Original").First()).AncestorsAndSelf().OfType(Of ClassDeclarationSyntax).First()
Dim results = Await codelensService.FindReferenceLocationsAsync(workspace.CurrentSolution, startDocument.Id, node, CancellationToken.None)
+ Assert.True(results.HasValue)
Dim definitionDocument = workspace.Documents.First(Function(d) d.AnnotatedSpans.ContainsKey("Definition"))
Dim definitionText = Await workspace.CurrentSolution.GetDocument(definitionDocument.Id).GetTextAsync()
@@ -152,7 +153,7 @@ class {|Definition:C1|}
Dim actual = New List(Of (String, LinePosition, String))
- For Each result In results
+ For Each result In results.Value
actual.Add((result.FilePath, New LinePosition(result.LineNumber, result.ColumnNumber), result.ReferenceLineText))
Next
diff --git a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs
index 062a5fac72e5d..4017dfb785d5d 100644
--- a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs
+++ b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
@@ -26,9 +27,13 @@ ValueTask GetSemanticClassificationsAsync(
/// first int is the index of classification type in , and the
/// second and third ints encode the span.
///
+ [DataContract]
internal sealed class SerializableClassifiedSpans
{
+ [DataMember(Order = 0)]
public List? ClassificationTypes;
+
+ [DataMember(Order = 1)]
public List? ClassificationTriples;
internal static SerializableClassifiedSpans Dehydrate(ImmutableArray classifiedSpans)
diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs b/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs
index c6600938ce0ed..a364fad975817 100644
--- a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs
+++ b/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs
@@ -4,26 +4,32 @@
#nullable enable
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.DesignerAttribute
{
///
/// Serialization typed used to pass information to/from OOP and VS.
///
+ [DataContract]
internal struct DesignerAttributeData
{
///
/// The category specified in a [DesignerCategory("...")] attribute.
///
+ [DataMember(Order = 0)]
public string? Category;
///
/// The document this applies to.
///
+ [DataMember(Order = 1)]
public DocumentId DocumentId;
///
/// Path for this .
///
+ [DataMember(Order = 2)]
public string FilePath;
}
}
diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs b/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs
similarity index 90%
rename from src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs
rename to src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs
index 4f2565e061768..d6a1c90950d69 100644
--- a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs
+++ b/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs
@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.DesignerAttribute
/// Interface to allow host (VS) to inform the OOP service to start incrementally analyzing and
/// reporting results back to the host.
///
- internal interface IRemoteDesignerAttributeService
+ internal interface IRemoteDesignerAttributeDiscoveryService
{
ValueTask StartScanningForDesignerAttributesAsync(CancellationToken cancellation);
}
diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
index 934f8e10f3cdd..c4b3bca3b5b58 100644
--- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
+++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
@@ -11,6 +11,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
@@ -21,32 +22,64 @@
namespace Microsoft.CodeAnalysis.Diagnostics
{
+ [DataContract]
internal sealed class DiagnosticData : IEquatable
{
+ [DataMember(Order = 0)]
public readonly string Id;
+
+ [DataMember(Order = 1)]
public readonly string Category;
+
+ [DataMember(Order = 2)]
public readonly string? Message;
+
+ [DataMember(Order = 3)]
public readonly string? ENUMessageForBingSearch;
+ [DataMember(Order = 4)]
public readonly DiagnosticSeverity Severity;
+
+ [DataMember(Order = 5)]
public readonly DiagnosticSeverity DefaultSeverity;
+
+ [DataMember(Order = 6)]
public readonly bool IsEnabledByDefault;
+
+ [DataMember(Order = 7)]
public readonly int WarningLevel;
+
+ [DataMember(Order = 8)]
public readonly IReadOnlyList CustomTags;
+
+ [DataMember(Order = 9)]
public readonly ImmutableDictionary Properties;
+ [DataMember(Order = 10)]
public readonly ProjectId? ProjectId;
+
+ [DataMember(Order = 11)]
public readonly DiagnosticDataLocation? DataLocation;
+
+ [DataMember(Order = 12)]
public readonly IReadOnlyCollection AdditionalLocations;
///
/// Language name () or null if the diagnostic is not associated with source code.
///
+ [DataMember(Order = 13)]
public readonly string? Language;
+ [DataMember(Order = 14)]
public readonly string? Title;
+
+ [DataMember(Order = 15)]
public readonly string? Description;
+
+ [DataMember(Order = 16)]
public readonly string? HelpLink;
+
+ [DataMember(Order = 17)]
public readonly bool IsSuppressed;
///
diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs
index b4e00bf899551..8a3715b98cee5 100644
--- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs
+++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs
@@ -4,33 +4,56 @@
#nullable enable
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
+ [DataContract]
internal sealed class DiagnosticDataLocation
{
+ [DataMember(Order = 0)]
public readonly DocumentId? DocumentId;
// text can be either given or calculated from original line/column
+ [DataMember(Order = 1)]
public readonly TextSpan? SourceSpan;
+ [DataMember(Order = 2)]
+ public readonly string? OriginalFilePath;
+
+ [DataMember(Order = 3)]
+ public readonly int OriginalStartLine;
+
+ [DataMember(Order = 4)]
+ public readonly int OriginalStartColumn;
+
+ [DataMember(Order = 5)]
+ public readonly int OriginalEndLine;
+
+ [DataMember(Order = 6)]
+ public readonly int OriginalEndColumn;
+
///
/// Null if path is not mapped and contains the actual path.
/// Note that the value might be a relative path. In that case should be used
/// as a base path for path resolution.
///
+ [DataMember(Order = 7)]
public readonly string? MappedFilePath;
+
+ [DataMember(Order = 8)]
public readonly int MappedStartLine;
+
+ [DataMember(Order = 9)]
public readonly int MappedStartColumn;
+
+ [DataMember(Order = 10)]
public readonly int MappedEndLine;
+
+ [DataMember(Order = 11)]
public readonly int MappedEndColumn;
- public readonly string? OriginalFilePath;
- public readonly int OriginalStartLine;
- public readonly int OriginalStartColumn;
- public readonly int OriginalEndLine;
- public readonly int OriginalEndColumn;
public DiagnosticDataLocation(
DocumentId? documentId = null,
diff --git a/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs b/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs
new file mode 100644
index 0000000000000..f13422cecdc79
--- /dev/null
+++ b/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Runtime.Serialization;
+using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
+
+namespace Microsoft.CodeAnalysis.Diagnostics
+{
+ [DataContract]
+ internal readonly struct SerializableDiagnosticAnalysisResults
+ {
+ public static readonly SerializableDiagnosticAnalysisResults Empty = new(
+ ImmutableArray<(string, SerializableDiagnosticMap)>.Empty,
+ ImmutableArray<(string, AnalyzerTelemetryInfo)>.Empty);
+
+ [DataMember(Order = 0)]
+ internal readonly ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> Diagnostics;
+
+ [DataMember(Order = 1)]
+ internal readonly ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo telemetry)> Telemetry;
+
+ public SerializableDiagnosticAnalysisResults(
+ ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> diagnostics,
+ ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)> telemetry)
+ {
+ Diagnostics = diagnostics;
+ Telemetry = telemetry;
+ }
+ }
+
+ [DataContract]
+ internal readonly struct SerializableDiagnosticMap
+ {
+ [DataMember(Order = 0)]
+ public readonly ImmutableArray<(DocumentId, ImmutableArray)> Syntax;
+
+ [DataMember(Order = 1)]
+ public readonly ImmutableArray<(DocumentId, ImmutableArray)> Semantic;
+
+ [DataMember(Order = 2)]
+ public readonly ImmutableArray<(DocumentId, ImmutableArray)> NonLocal;
+
+ [DataMember(Order = 3)]
+ public readonly ImmutableArray Other;
+
+ public SerializableDiagnosticMap(
+ ImmutableArray<(DocumentId, ImmutableArray)> syntax,
+ ImmutableArray<(DocumentId, ImmutableArray)> semantic,
+ ImmutableArray<(DocumentId, ImmutableArray)> nonLocal,
+ ImmutableArray other)
+ {
+ Syntax = syntax;
+ Semantic = semantic;
+ NonLocal = nonLocal;
+ Other = other;
+ }
+ }
+}
diff --git a/src/Workspaces/Core/Portable/ExtensionManager/IErrorReportingService.cs b/src/Workspaces/Core/Portable/ExtensionManager/IErrorReportingService.cs
index d95e110c16773..465dd29994310 100644
--- a/src/Workspaces/Core/Portable/ExtensionManager/IErrorReportingService.cs
+++ b/src/Workspaces/Core/Portable/ExtensionManager/IErrorReportingService.cs
@@ -11,6 +11,11 @@ namespace Microsoft.CodeAnalysis.Extensions
{
internal interface IErrorReportingService : IWorkspaceService
{
+ ///
+ /// Name of the host to be used in error messages (e.g. "Visual Studio").
+ ///
+ string HostDisplayName { get; }
+
///
/// Show error info in an active view.
///
@@ -31,7 +36,12 @@ internal interface IErrorReportingService : IWorkspaceService
///
/// Shows info-bar reporting ServiceHub process crash.
/// "Unfortunately a process used by Visual Studio has encountered an unrecoverable error".
+ ///
+ /// Obsolete - will remove once we remove JsonRpcConnection.
+ /// https://github.com/dotnet/roslyn/issues/45859
///
void ShowRemoteHostCrashedErrorInfo(Exception? exception);
+
+ void ShowFeatureNotAvailableErrorInfo(string message, Exception? exception);
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
index 2226c881f907c..4160004b0785c 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
@@ -41,15 +41,18 @@ public static async Task> FindAllDeclarationsWithNormalQ
{
var solution = project.Solution;
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindAllDeclarationsWithNormalQueryAsync),
+ var result = await client.TryInvokeAsync>(
solution,
- new object[] { project.Id, query.Name, query.Kind, criteria },
+ (service, solutionInfo, cancellationToken) => service.FindAllDeclarationsWithNormalQueryAsync(solutionInfo, project.Id, query.Name, query.Kind, criteria, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false);
}
return await FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
diff --git a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
index 50bab9639d6de..c8c65209cf36e 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
@@ -44,15 +44,18 @@ public static async Task> FindSourceDeclarationsWithNorm
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithNormalQueryAsync),
+ var result = await client.TryInvokeAsync>(
solution,
- new object[] { name, ignoreCase, criteria },
+ (service, solutionInfo, cancellationToken) => service.FindSolutionSourceDeclarationsWithNormalQueryAsync(solutionInfo, name, ignoreCase, criteria, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false);
}
return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
@@ -80,15 +83,18 @@ public static async Task> FindSourceDeclarationsWithNorm
var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithNormalQueryAsync),
+ var result = await client.TryInvokeAsync>(
project.Solution,
- new object[] { project.Id, name, ignoreCase, criteria },
+ (service, solutionInfo, cancellationToken) => service.FindProjectSourceDeclarationsWithNormalQueryAsync(solutionInfo, project.Id, name, ignoreCase, criteria, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(project.Solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return await RehydrateAsync(project.Solution, result.Value, cancellationToken).ConfigureAwait(false);
}
return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
@@ -111,15 +117,18 @@ public static async Task> FindSourceDeclarationsWithPatt
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithPatternAsync),
+ var result = await client.TryInvokeAsync>(
solution,
- new object[] { pattern, criteria },
+ (service, solutionInfo, cancellationToken) => service.FindSolutionSourceDeclarationsWithPatternAsync(solutionInfo, pattern, criteria, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false);
}
return await FindSourceDeclarationsWithPatternInCurrentProcessAsync(
@@ -142,15 +151,18 @@ public static async Task> FindSourceDeclarationsWithPatt
var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithPatternAsync),
+ var result = await client.TryInvokeAsync>(
project.Solution,
- new object[] { project.Id, pattern, criteria },
+ (service, solutionInfo, cancellationToken) => service.FindProjectSourceDeclarationsWithPatternAsync(solutionInfo, project.Id, pattern, criteria, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(project.Solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ return await RehydrateAsync(project.Solution, result.Value, cancellationToken).ConfigureAwait(false);
}
return await FindSourceDeclarationsWithPatternInCurrentProcessAsync(
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
index 8ce7208f93db0..13f3de4b0392d 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder.cs
@@ -62,7 +62,7 @@ internal static partial class DependentTypeFinder
private static async Task> DescendInheritanceTreeAsync(
INamedTypeSymbol type,
Solution solution,
- IImmutableSet projects,
+ IImmutableSet? projects,
Func typeMatches,
Func shouldContinueSearching,
bool transitive,
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs
index 8087a7201385d..0d1610aa035f7 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs
@@ -8,45 +8,22 @@
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Internal.Log;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
- using SymbolSet = HashSet;
-
internal static partial class DependentTypeFinder
{
- public static async Task> FindDerivedClassesAsync(
- INamedTypeSymbol type,
- Solution solution,
- IImmutableSet projects,
- bool transitive,
- CancellationToken cancellationToken)
- {
- var result = await TryFindRemoteTypesAsync(
- type, solution, projects, transitive,
- FunctionId.DependentTypeFinder_FindAndCacheDerivedClassesAsync,
- nameof(IRemoteDependentTypeFinder.FindDerivedClassesAsync),
- cancellationToken).ConfigureAwait(false);
-
- if (result.HasValue)
- return result.Value;
-
- return await FindDerivedClassesInCurrentProcessAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
- }
-
private static Task> FindDerivedClassesInCurrentProcessAsync(
INamedTypeSymbol type,
Solution solution,
- IImmutableSet projects,
+ IImmutableSet? projects,
bool transitive,
CancellationToken cancellationToken)
{
if (s_isNonSealedClass(type))
{
- static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
+ static bool TypeMatches(INamedTypeSymbol type, HashSet set)
=> TypeHasBaseTypeInSet(type, set);
return DescendInheritanceTreeAsync(type, solution, projects,
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs
index 83c69d9b29e8f..2968cb04f7031 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs
@@ -13,41 +13,19 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
- using SymbolSet = HashSet;
-
internal static partial class DependentTypeFinder
{
- public static async Task> FindDerivedInterfacesAsync(
- INamedTypeSymbol type,
- Solution solution,
- IImmutableSet projects,
- bool transitive,
- CancellationToken cancellationToken)
- {
- var result = await TryFindRemoteTypesAsync(
- type, solution, projects, transitive,
- FunctionId.DependentTypeFinder_FindAndCacheDerivedInterfacesAsync,
- nameof(IRemoteDependentTypeFinder.FindDerivedInterfacesAsync),
- cancellationToken).ConfigureAwait(false);
-
- if (result.HasValue)
- return result.Value;
-
- return await FindDerivedInterfacesInCurrentProcessAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
- }
-
private static Task> FindDerivedInterfacesInCurrentProcessAsync(
INamedTypeSymbol type,
Solution solution,
- IImmutableSet projects,
+ IImmutableSet? projects,
bool transitive,
CancellationToken cancellationToken)
{
// Only an interface can be implemented.
if (s_isInterface(type))
{
- static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
+ static bool TypeMatches(INamedTypeSymbol type, HashSet set)
=> s_isInterface(type) && TypeHasInterfaceInSet(type, set);
return DescendInheritanceTreeAsync(type, solution, projects,
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs
index fb5da99be31f5..97b4288b65f85 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs
@@ -8,38 +8,15 @@
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Internal.Log;
namespace Microsoft.CodeAnalysis.FindSymbols
{
- using SymbolSet = HashSet;
-
internal static partial class DependentTypeFinder
{
- public static async Task> FindImplementingTypesAsync(
- INamedTypeSymbol type,
- Solution solution,
- IImmutableSet projects,
- bool transitive,
- CancellationToken cancellationToken)
- {
- var result = await TryFindRemoteTypesAsync(
- type, solution, projects, transitive,
- FunctionId.DependentTypeFinder_FindAndCacheImplementingTypesAsync,
- nameof(IRemoteDependentTypeFinder.FindImplementingTypesAsync),
- cancellationToken).ConfigureAwait(false);
-
- if (result.HasValue)
- return result.Value;
-
- return await FindImplementingTypesInCurrentProcessAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
- }
-
private static async Task> FindImplementingTypesInCurrentProcessAsync(
INamedTypeSymbol type,
Solution solution,
- IImmutableSet projects,
+ IImmutableSet? projects,
bool transitive,
CancellationToken cancellationToken)
{
@@ -59,7 +36,7 @@ private static async Task> FindImplementingType
// 'Base' match and will add to the set. Then, we'll look for types that have 'Base' in their
// inheritance chain, and we need to match that by looking in the .BaseType inheritance chain when
// looking at 'Derived'.
- static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
+ static bool TypeMatches(INamedTypeSymbol type, HashSet set)
=> TypeHasBaseTypeInSet(type, set) || TypeHasInterfaceInSet(type, set);
// As long as we keep hitting derived interfaces or implementing non-sealed classes we need to keep
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs
index 516b9899a347c..79c01bc5faec3 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs
@@ -4,6 +4,7 @@
#nullable enable
+using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
@@ -11,46 +12,75 @@
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Remote;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
internal static partial class DependentTypeFinder
{
- public static async Task?> TryFindRemoteTypesAsync(
+ public static async Task> FindTypesAsync(
INamedTypeSymbol type,
Solution solution,
- IImmutableSet projects,
+ IImmutableSet? projects,
bool transitive,
- FunctionId functionId,
- string remoteFunctionName,
+ DependentTypesKind kind,
CancellationToken cancellationToken)
{
- using (Logger.LogBlock(functionId, cancellationToken))
+ if (SerializableSymbolAndProjectId.TryCreate(type, solution, cancellationToken, out var serializedType))
{
- if (SerializableSymbolAndProjectId.TryCreate(type, solution, cancellationToken, out var serializedType))
+ var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
+ if (client != null)
{
- var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
- if (client != null)
- {
- var result = await client.RunRemoteAsync>(
- WellKnownServiceHubService.CodeAnalysis,
- remoteFunctionName,
- solution,
- new object?[]
- {
- serializedType,
- projects?.Select(p => p.Id).ToArray(),
- transitive,
- },
- null,
- cancellationToken).ConfigureAwait(false);
+ var projectIds = projects?.SelectAsArray(p => p.Id) ?? default;
+
+ var result = await client.TryInvokeAsync>(
+ solution,
+ (service, solutionInfo, cancellationToken) => service.FindTypesAsync(solutionInfo, serializedType, projectIds, transitive, kind, cancellationToken),
+ callbackTarget: null,
+ cancellationToken).ConfigureAwait(false);
- return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false);
+ if (!result.HasValue)
+ {
+ return ImmutableArray.Empty;
}
+
+ return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false);
}
+
+ // TODO: Do not fall back to in-proc https://github.com/dotnet/roslyn/issues/47557
}
- return null;
+ return await FindTypesInCurrentProcessAsync(type, solution, projects, transitive, kind, cancellationToken).ConfigureAwait(false);
+ }
+
+ public static async Task> FindTypesInCurrentProcessAsync(
+ INamedTypeSymbol type,
+ Solution solution,
+ IImmutableSet? projects,
+ bool transitive,
+ DependentTypesKind kind,
+ CancellationToken cancellationToken)
+ {
+ var functionId = kind switch
+ {
+ DependentTypesKind.DerivedClasses => FunctionId.DependentTypeFinder_FindAndCacheDerivedClassesAsync,
+ DependentTypesKind.DerivedInterfaces => FunctionId.DependentTypeFinder_FindAndCacheDerivedInterfacesAsync,
+ DependentTypesKind.ImplementingTypes => FunctionId.DependentTypeFinder_FindAndCacheImplementingTypesAsync,
+ _ => throw ExceptionUtilities.UnexpectedValue(kind)
+ };
+
+ using (Logger.LogBlock(functionId, cancellationToken))
+ {
+ var task = kind switch
+ {
+ DependentTypesKind.DerivedClasses => FindDerivedClassesInCurrentProcessAsync(type, solution, projects, transitive, cancellationToken),
+ DependentTypesKind.DerivedInterfaces => FindDerivedInterfacesInCurrentProcessAsync(type, solution, projects, transitive, cancellationToken),
+ DependentTypesKind.ImplementingTypes => FindImplementingTypesInCurrentProcessAsync(type, solution, projects, transitive, cancellationToken),
+ _ => throw ExceptionUtilities.UnexpectedValue(kind)
+ };
+
+ return await task.ConfigureAwait(false);
+ }
}
private static async Task> RehydrateAsync(Solution solution, ImmutableArray values, CancellationToken cancellationToken)
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypesKind.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypesKind.cs
new file mode 100644
index 0000000000000..0a87cbfc930c2
--- /dev/null
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypesKind.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.CodeAnalysis.FindSymbols
+{
+ internal enum DependentTypesKind
+ {
+ DerivedClasses,
+ DerivedInterfaces,
+ ImplementingTypes
+ }
+}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs
index cb0779667f234..82c8473e56ab1 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.cs
@@ -113,7 +113,7 @@ private static void ValidateProjectToDocumentMap(
}
}
- private Task HandleLocationAsync(ISymbol symbol, ReferenceLocation location)
+ private ValueTask HandleLocationAsync(ISymbol symbol, ReferenceLocation location)
=> _progress.OnReferenceFoundAsync(symbol, location);
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs
index c7b4b56426f88..5553edcac308c 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs
@@ -2,11 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.FindSymbols
{
- internal class FindReferencesSearchOptions
+ [DataContract]
+ internal sealed class FindReferencesSearchOptions
{
public static readonly FindReferencesSearchOptions Default =
new FindReferencesSearchOptions(
@@ -25,12 +27,14 @@ internal class FindReferencesSearchOptions
/// The default for this is false. With that default, all of the above references
/// are associated with the property P and not the accessors.
///
+ [DataMember(Order = 0)]
public bool AssociatePropertyReferencesWithSpecificAccessor { get; }
///
/// Whether or not we should cascade from the original search symbol to new symbols as we're
/// doing the find-references search.
///
+ [DataMember(Order = 1)]
public bool Cascade { get; }
public FindReferencesSearchOptions(
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinder.cs
deleted file mode 100644
index 0c019db1d97db..0000000000000
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinder.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Immutable;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Remote;
-
-namespace Microsoft.CodeAnalysis.FindSymbols
-{
- internal interface IRemoteDependentTypeFinder
- {
- Task> FindDerivedClassesAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId type,
- ProjectId[] projects,
- bool transitive,
- CancellationToken cancellationToken);
-
- Task> FindDerivedInterfacesAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId type,
- ProjectId[] projects,
- bool transitive,
- CancellationToken cancellationToken);
-
- Task> FindImplementingTypesAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId type,
- ProjectId[] projects,
- bool transitive,
- CancellationToken cancellationToken);
- }
-}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinderService.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinderService.cs
new file mode 100644
index 0000000000000..476787d2bd7ea
--- /dev/null
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinderService.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Remote;
+
+namespace Microsoft.CodeAnalysis.FindSymbols
+{
+ internal interface IRemoteDependentTypeFinderService
+ {
+ ValueTask> FindTypesAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId type,
+ ImmutableArray projectsOpt,
+ bool transitive,
+ DependentTypesKind kind,
+ CancellationToken cancellationToken);
+ }
+}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs
index 065d32c831e9c..aed4162ab5821 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs
@@ -26,17 +26,17 @@ private NoOpStreamingFindReferencesProgress()
public static Task ReportProgressAsync(int current, int maximum) => Task.CompletedTask;
#pragma warning restore IDE0060 // Remove unused parameter
- public Task OnCompletedAsync() => Task.CompletedTask;
- public Task OnStartedAsync() => Task.CompletedTask;
- public Task OnDefinitionFoundAsync(ISymbol symbol) => Task.CompletedTask;
- public Task OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location) => Task.CompletedTask;
- public Task OnFindInDocumentStartedAsync(Document document) => Task.CompletedTask;
- public Task OnFindInDocumentCompletedAsync(Document document) => Task.CompletedTask;
+ public ValueTask OnCompletedAsync() => default;
+ public ValueTask OnStartedAsync() => default;
+ public ValueTask OnDefinitionFoundAsync(ISymbol symbol) => default;
+ public ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location) => default;
+ public ValueTask OnFindInDocumentStartedAsync(Document document) => default;
+ public ValueTask OnFindInDocumentCompletedAsync(Document document) => default;
private class NoOpProgressTracker : IStreamingProgressTracker
{
- public Task AddItemsAsync(int count) => Task.CompletedTask;
- public Task ItemCompletedAsync() => Task.CompletedTask;
+ public ValueTask AddItemsAsync(int count) => default;
+ public ValueTask ItemCompletedAsync() => default;
}
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs
index c9e46f9d5e03b..9c662202a1412 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs
@@ -20,47 +20,47 @@ internal class StreamingFindReferencesProgressAdapter : IStreamingFindReferences
public StreamingFindReferencesProgressAdapter(IFindReferencesProgress progress)
{
_progress = progress;
- this.ProgressTracker = new StreamingProgressTracker((current, max) =>
+ ProgressTracker = new StreamingProgressTracker((current, max) =>
{
_progress.ReportProgress(current, max);
- return Task.CompletedTask;
+ return default;
});
}
- public Task OnCompletedAsync()
+ public ValueTask OnCompletedAsync()
{
_progress.OnCompleted();
- return Task.CompletedTask;
+ return default;
}
- public Task OnDefinitionFoundAsync(ISymbol symbol)
+ public ValueTask OnDefinitionFoundAsync(ISymbol symbol)
{
_progress.OnDefinitionFound(symbol);
- return Task.CompletedTask;
+ return default;
}
- public Task OnFindInDocumentCompletedAsync(Document document)
+ public ValueTask OnFindInDocumentCompletedAsync(Document document)
{
_progress.OnFindInDocumentCompleted(document);
- return Task.CompletedTask;
+ return default;
}
- public Task OnFindInDocumentStartedAsync(Document document)
+ public ValueTask OnFindInDocumentStartedAsync(Document document)
{
_progress.OnFindInDocumentStarted(document);
- return Task.CompletedTask;
+ return default;
}
- public Task OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location)
+ public ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location)
{
_progress.OnReferenceFound(symbol, location);
- return Task.CompletedTask;
+ return default;
}
- public Task OnStartedAsync()
+ public ValueTask OnStartedAsync()
{
_progress.OnStarted();
- return Task.CompletedTask;
+ return default;
}
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs
deleted file mode 100644
index 24169be4667a2..0000000000000
--- a/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Immutable;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Remote;
-
-namespace Microsoft.CodeAnalysis.FindSymbols
-{
- internal interface IRemoteSymbolFinder
- {
- Task FindReferencesAsync(PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbolAndProjectIdArg, DocumentId[] documentArgs,
- SerializableFindReferencesSearchOptions options, CancellationToken cancellationToken);
-
- Task FindLiteralReferencesAsync(PinnedSolutionInfo solutionInfo, object value, TypeCode typeCode, CancellationToken cancellationToken);
-
- Task> FindAllDeclarationsWithNormalQueryAsync(
- PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, SearchKind searchKind, SymbolFilter criteria, CancellationToken cancellationToken);
-
- Task> FindSolutionSourceDeclarationsWithNormalQueryAsync(
- PinnedSolutionInfo solutionInfo, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken);
-
- Task> FindProjectSourceDeclarationsWithNormalQueryAsync(
- PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken);
-
- Task> FindSolutionSourceDeclarationsWithPatternAsync(
- PinnedSolutionInfo solutionInfo, string pattern, SymbolFilter criteria, CancellationToken cancellationToken);
-
- Task> FindProjectSourceDeclarationsWithPatternAsync(
- PinnedSolutionInfo solutionInfo, ProjectId projectId, string pattern, SymbolFilter criteria, CancellationToken cancellationToken);
- }
-}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinderService.cs b/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinderService.cs
new file mode 100644
index 0000000000000..16eb7e98718aa
--- /dev/null
+++ b/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinderService.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.FindSymbols
+{
+ internal interface IRemoteSymbolFinderService
+ {
+ internal interface ICallback
+ {
+ ValueTask AddItemsAsync(int count);
+ ValueTask ItemCompletedAsync();
+ ValueTask OnStartedAsync();
+ ValueTask OnCompletedAsync();
+ ValueTask OnFindInDocumentStartedAsync(DocumentId documentId);
+ ValueTask OnFindInDocumentCompletedAsync(DocumentId documentId);
+ ValueTask OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition);
+ ValueTask OnReferenceFoundAsync(SerializableSymbolAndProjectId definition, SerializableReferenceLocation reference);
+ ValueTask OnLiteralReferenceFoundAsync(DocumentId documentId, TextSpan span);
+ }
+
+ ValueTask FindReferencesAsync(PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbolAndProjectIdArg, ImmutableArray documentArgs,
+ FindReferencesSearchOptions options, CancellationToken cancellationToken);
+
+ ValueTask FindLiteralReferencesAsync(PinnedSolutionInfo solutionInfo, object value, TypeCode typeCode, CancellationToken cancellationToken);
+
+ ValueTask> FindAllDeclarationsWithNormalQueryAsync(
+ PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, SearchKind searchKind, SymbolFilter criteria, CancellationToken cancellationToken);
+
+ ValueTask> FindSolutionSourceDeclarationsWithNormalQueryAsync(
+ PinnedSolutionInfo solutionInfo, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken);
+
+ ValueTask> FindProjectSourceDeclarationsWithNormalQueryAsync(
+ PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken);
+
+ ValueTask> FindSolutionSourceDeclarationsWithPatternAsync(
+ PinnedSolutionInfo solutionInfo, string pattern, SymbolFilter criteria, CancellationToken cancellationToken);
+
+ ValueTask> FindProjectSourceDeclarationsWithPatternAsync(
+ PinnedSolutionInfo solutionInfo, ProjectId projectId, string pattern, SymbolFilter criteria, CancellationToken cancellationToken);
+ }
+}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs
index d05e6732d9104..8f69f00766c8c 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs
@@ -16,20 +16,20 @@ internal interface IStreamingFindReferencesProgress
{
IStreamingProgressTracker ProgressTracker { get; }
- Task OnStartedAsync();
- Task OnCompletedAsync();
+ ValueTask OnStartedAsync();
+ ValueTask OnCompletedAsync();
- Task OnFindInDocumentStartedAsync(Document document);
- Task OnFindInDocumentCompletedAsync(Document document);
+ ValueTask OnFindInDocumentStartedAsync(Document document);
+ ValueTask OnFindInDocumentCompletedAsync(Document document);
- Task OnDefinitionFoundAsync(ISymbol symbol);
- Task OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location);
+ ValueTask OnDefinitionFoundAsync(ISymbol symbol);
+ ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location);
}
internal interface IStreamingFindLiteralReferencesProgress
{
IStreamingProgressTracker ProgressTracker { get; }
- Task OnReferenceFoundAsync(Document document, TextSpan span);
+ ValueTask OnReferenceFoundAsync(Document document, TextSpan span);
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs
index fb3bf5876c39f..5187ad6dc79a1 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs
@@ -53,13 +53,13 @@ public ImmutableArray GetReferencedSymbols()
}
}
- public Task OnStartedAsync() => _underlyingProgress.OnStartedAsync();
- public Task OnCompletedAsync() => _underlyingProgress.OnCompletedAsync();
+ public ValueTask OnStartedAsync() => _underlyingProgress.OnStartedAsync();
+ public ValueTask OnCompletedAsync() => _underlyingProgress.OnCompletedAsync();
- public Task OnFindInDocumentCompletedAsync(Document document) => _underlyingProgress.OnFindInDocumentCompletedAsync(document);
- public Task OnFindInDocumentStartedAsync(Document document) => _underlyingProgress.OnFindInDocumentStartedAsync(document);
+ public ValueTask OnFindInDocumentCompletedAsync(Document document) => _underlyingProgress.OnFindInDocumentCompletedAsync(document);
+ public ValueTask OnFindInDocumentStartedAsync(Document document) => _underlyingProgress.OnFindInDocumentStartedAsync(document);
- public Task OnDefinitionFoundAsync(ISymbol definition)
+ public ValueTask OnDefinitionFoundAsync(ISymbol definition)
{
lock (_gate)
{
@@ -69,7 +69,7 @@ public Task OnDefinitionFoundAsync(ISymbol definition)
return _underlyingProgress.OnDefinitionFoundAsync(definition);
}
- public Task OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location)
+ public ValueTask OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location)
{
lock (_gate)
{
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs
index fe4999b7874ef..08ff7c0808362 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs
@@ -3,13 +3,15 @@
// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
public static partial class SymbolFinder
{
- internal sealed class FindLiteralsServerCallback
+ internal sealed class FindLiteralsServerCallback : IRemoteSymbolFinderService.ICallback
{
private readonly Solution _solution;
private readonly IStreamingFindLiteralReferencesProgress _progress;
@@ -22,18 +24,35 @@ public FindLiteralsServerCallback(
_progress = progress;
}
- public Task AddItemsAsync(int count)
+ public ValueTask AddItemsAsync(int count)
=> _progress.ProgressTracker.AddItemsAsync(count);
- public Task ItemCompletedAsync()
+ public ValueTask ItemCompletedAsync()
=> _progress.ProgressTracker.ItemCompletedAsync();
- public async Task OnReferenceFoundAsync(
- DocumentId documentId, TextSpan span)
+ public async ValueTask OnLiteralReferenceFoundAsync(DocumentId documentId, TextSpan span)
{
var document = _solution.GetDocument(documentId);
await _progress.OnReferenceFoundAsync(document, span).ConfigureAwait(false);
}
+
+ public ValueTask OnCompletedAsync()
+ => throw ExceptionUtilities.Unreachable;
+
+ public ValueTask OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition)
+ => throw ExceptionUtilities.Unreachable;
+
+ public ValueTask OnFindInDocumentCompletedAsync(DocumentId documentId)
+ => throw ExceptionUtilities.Unreachable;
+
+ public ValueTask OnFindInDocumentStartedAsync(DocumentId documentId)
+ => throw ExceptionUtilities.Unreachable;
+
+ public ValueTask OnReferenceFoundAsync(SerializableSymbolAndProjectId definition, SerializableReferenceLocation reference)
+ => throw ExceptionUtilities.Unreachable;
+
+ public ValueTask OnStartedAsync()
+ => throw ExceptionUtilities.Unreachable;
}
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs
index 656c0c0599f33..781bcabbe7f80 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs
@@ -6,6 +6,8 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
@@ -15,7 +17,7 @@ public static partial class SymbolFinder
/// Callback object we pass to the OOP server to hear about the result
/// of the FindReferencesEngine as it executes there.
///
- internal sealed class FindReferencesServerCallback : IEqualityComparer
+ internal sealed class FindReferencesServerCallback : IRemoteSymbolFinderService.ICallback, IEqualityComparer
{
private readonly Solution _solution;
private readonly IStreamingFindReferencesProgress _progress;
@@ -35,25 +37,25 @@ public FindReferencesServerCallback(
_definitionMap = new Dictionary(this);
}
- public Task AddItemsAsync(int count) => _progress.ProgressTracker.AddItemsAsync(count);
- public Task ItemCompletedAsync() => _progress.ProgressTracker.ItemCompletedAsync();
+ public ValueTask AddItemsAsync(int count) => _progress.ProgressTracker.AddItemsAsync(count);
+ public ValueTask ItemCompletedAsync() => _progress.ProgressTracker.ItemCompletedAsync();
- public Task OnStartedAsync() => _progress.OnStartedAsync();
- public Task OnCompletedAsync() => _progress.OnCompletedAsync();
+ public ValueTask OnStartedAsync() => _progress.OnStartedAsync();
+ public ValueTask OnCompletedAsync() => _progress.OnCompletedAsync();
- public Task OnFindInDocumentStartedAsync(DocumentId documentId)
+ public ValueTask OnFindInDocumentStartedAsync(DocumentId documentId)
{
var document = _solution.GetDocument(documentId);
return _progress.OnFindInDocumentStartedAsync(document);
}
- public Task OnFindInDocumentCompletedAsync(DocumentId documentId)
+ public ValueTask OnFindInDocumentCompletedAsync(DocumentId documentId)
{
var document = _solution.GetDocument(documentId);
return _progress.OnFindInDocumentCompletedAsync(document);
}
- public async Task OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition)
+ public async ValueTask OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition)
{
var symbol = await definition.TryRehydrateAsync(
_solution, _cancellationToken).ConfigureAwait(false);
@@ -69,7 +71,7 @@ public async Task OnDefinitionFoundAsync(SerializableSymbolAndProjectId definiti
await _progress.OnDefinitionFoundAsync(symbol).ConfigureAwait(false);
}
- public async Task OnReferenceFoundAsync(
+ public async ValueTask OnReferenceFoundAsync(
SerializableSymbolAndProjectId definition, SerializableReferenceLocation reference)
{
ISymbol symbol;
@@ -97,6 +99,9 @@ bool IEqualityComparer.Equals(SerializableSymbol
int IEqualityComparer.GetHashCode(SerializableSymbolAndProjectId obj)
=> obj.SymbolKeyData.GetHashCode();
+
+ public ValueTask OnLiteralReferenceFoundAsync(DocumentId documentId, TextSpan span)
+ => throw ExceptionUtilities.Unreachable;
}
}
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs
index e7b0da751212b..5095a860c5867 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs
@@ -29,11 +29,9 @@ internal static async Task FindLiteralReferencesAsync(
// the 'progress' parameter which will then update the UI.
var serverCallback = new FindLiteralsServerCallback(solution, progress);
- await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindLiteralReferencesAsync),
+ _ = await client.TryInvokeAsync(
solution,
- new object[] { value, typeCode },
+ (service, solutionInfo, cancellationToken) => service.FindLiteralReferencesAsync(solutionInfo, value, typeCode, cancellationToken),
serverCallback,
cancellationToken).ConfigureAwait(false);
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs
index 397e278440eff..8fcb8ca396f7f 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs
@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.FindSymbols.Finders;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Remote;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
@@ -37,17 +38,11 @@ internal static async Task FindReferencesAsync(
// results as it finds them. When we hear about results we'll forward them to
// the 'progress' parameter which will then update the UI.
var serverCallback = new FindReferencesServerCallback(solution, progress, cancellationToken);
+ var documentIds = documents?.SelectAsArray(d => d.Id) ?? default;
- await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteSymbolFinder.FindReferencesAsync),
+ await client.TryInvokeAsync(
solution,
- new object[]
- {
- serializedSymbol,
- documents?.Select(d => d.Id).ToArray(),
- SerializableFindReferencesSearchOptions.Dehydrate(options),
- },
+ (service, solutionInfo, cancellationToken) => service.FindReferencesAsync(solutionInfo, serializedSymbol, documentIds, options, cancellationToken),
serverCallback,
cancellationToken).ConfigureAwait(false);
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs
index 7a2922d5c79e8..bb4c53c42e339 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Hierarchy.cs
@@ -212,8 +212,8 @@ public static async Task> FindDerivedClassesAsync(
internal static async Task> FindDerivedClassesArrayAsync(
INamedTypeSymbol type, Solution solution, bool transitive, IImmutableSet projects = null, CancellationToken cancellationToken = default)
{
- var types = await DependentTypeFinder.FindDerivedClassesAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
+ var types = await DependentTypeFinder.FindTypesAsync(
+ type, solution, projects, transitive, DependentTypesKind.DerivedClasses, cancellationToken).ConfigureAwait(false);
return types.WhereAsArray(t => IsAccessible(t));
}
@@ -248,8 +248,8 @@ public static async Task> FindDerivedInterfacesAsy
internal static async Task> FindDerivedInterfacesArrayAsync(
INamedTypeSymbol type, Solution solution, bool transitive, IImmutableSet projects = null, CancellationToken cancellationToken = default)
{
- var types = await DependentTypeFinder.FindDerivedInterfacesAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
+ var types = await DependentTypeFinder.FindTypesAsync(
+ type, solution, projects, transitive, DependentTypesKind.DerivedInterfaces, cancellationToken).ConfigureAwait(false);
return types.WhereAsArray(t => IsAccessible(t));
}
@@ -284,8 +284,8 @@ public static async Task> FindImplementationsAsync
internal static async Task> FindImplementationsArrayAsync(
INamedTypeSymbol type, Solution solution, bool transitive, IImmutableSet projects = null, CancellationToken cancellationToken = default)
{
- var types = await DependentTypeFinder.FindImplementingTypesAsync(
- type, solution, projects, transitive, cancellationToken).ConfigureAwait(false);
+ var types = await DependentTypeFinder.FindTypesAsync(
+ type, solution, projects, transitive, DependentTypesKind.ImplementingTypes, cancellationToken).ConfigureAwait(false);
return types.WhereAsArray(t => IsAccessible(t));
}
diff --git a/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs b/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs
index 0ab4460adf21e..8c68787296e5d 100644
--- a/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs
+++ b/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
@@ -42,9 +43,13 @@ bool TryInstallPackage(Workspace workspace, DocumentId documentId,
event EventHandler PackageSourcesChanged;
}
- internal struct PackageSource : IEquatable
+ [DataContract]
+ internal readonly struct PackageSource : IEquatable
{
+ [DataMember(Order = 0)]
public readonly string Name;
+
+ [DataMember(Order = 1)]
public readonly string Source;
public PackageSource(string name, string source)
@@ -54,7 +59,7 @@ public PackageSource(string name, string source)
}
public override bool Equals(object obj)
- => Equals((PackageSource)obj);
+ => obj is PackageSource source && Equals(source);
public bool Equals(PackageSource other)
=> Name == other.Name && Source == other.Source;
diff --git a/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs b/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs
index b4a2a628f9db2..b5a83c34538e8 100644
--- a/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs
+++ b/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs
@@ -4,20 +4,47 @@
#nullable enable
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.ProjectTelemetry
{
///
/// Serialization typed used to pass information to/from OOP and VS.
///
- internal struct ProjectTelemetryData
+ [DataContract]
+ internal readonly struct ProjectTelemetryData
{
- public ProjectId ProjectId;
- public string Language;
- public int AnalyzerReferencesCount;
- public int ProjectReferencesCount;
- public int MetadataReferencesCount;
- public int DocumentsCount;
- public int AdditionalDocumentsCount;
+ [DataMember(Order = 0)]
+ public readonly ProjectId ProjectId;
+
+ [DataMember(Order = 1)]
+ public readonly string Language;
+
+ [DataMember(Order = 2)]
+ public readonly int AnalyzerReferencesCount;
+
+ [DataMember(Order = 3)]
+ public readonly int ProjectReferencesCount;
+
+ [DataMember(Order = 4)]
+ public readonly int MetadataReferencesCount;
+
+ [DataMember(Order = 5)]
+ public readonly int DocumentsCount;
+
+ [DataMember(Order = 6)]
+ public readonly int AdditionalDocumentsCount;
+
+ public ProjectTelemetryData(ProjectId projectId, string language, int analyzerReferencesCount, int projectReferencesCount, int metadataReferencesCount, int documentsCount, int additionalDocumentsCount)
+ {
+ ProjectId = projectId;
+ Language = language;
+ AnalyzerReferencesCount = analyzerReferencesCount;
+ ProjectReferencesCount = projectReferencesCount;
+ MetadataReferencesCount = metadataReferencesCount;
+ DocumentsCount = documentsCount;
+ AdditionalDocumentsCount = additionalDocumentsCount;
+ }
public bool Equals(ProjectTelemetryData other)
=> Language.Equals(other.Language) &&
diff --git a/src/Workspaces/Core/Portable/Remote/IRemoteHostClientShutdownCancellationService.cs b/src/Workspaces/Core/Portable/Remote/IRemoteHostClientShutdownCancellationService.cs
new file mode 100644
index 0000000000000..8dda5e81226d7
--- /dev/null
+++ b/src/Workspaces/Core/Portable/Remote/IRemoteHostClientShutdownCancellationService.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using Microsoft.CodeAnalysis.Host;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ // TODO: consider consolidating this with IThreadingContext.DisposalToken
+ // https://github.com/dotnet/roslyn/issues/47840
+ internal interface IRemoteHostClientShutdownCancellationService : IWorkspaceService
+ {
+ ///
+ /// Token signaled when the host starts to shut down.
+ ///
+ CancellationToken ShutdownToken { get; }
+ }
+}
diff --git a/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs b/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs
index 3c292fe7b6487..c4a3ccb289e00 100644
--- a/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs
+++ b/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs
@@ -4,11 +4,14 @@
#nullable enable
+using System.Runtime.Serialization;
+
namespace Microsoft.CodeAnalysis.Remote
{
///
/// Information related to pinned solution
///
+ [DataContract]
internal sealed class PinnedSolutionInfo
{
///
@@ -16,6 +19,7 @@ internal sealed class PinnedSolutionInfo
///
/// This later used to find matching solution between VS and remote host
///
+ [DataMember(Order = 0)]
public readonly int ScopeId;
///
@@ -24,14 +28,17 @@ internal sealed class PinnedSolutionInfo
/// Features like OOP will use this flag to see whether caching information related to this solution
/// can benefit other requests or not
///
+ [DataMember(Order = 1)]
public readonly bool FromPrimaryBranch;
///
/// This indicates a Solution.WorkspaceVersion of this solution. remote host engine uses this version
/// to decide whether caching this solution will benefit other requests or not
///
+ [DataMember(Order = 2)]
public readonly int WorkspaceVersion;
+ [DataMember(Order = 3)]
public readonly Checksum SolutionChecksum;
public PinnedSolutionInfo(int scopeId, bool fromPrimaryBranch, int workspaceVersion, Checksum solutionChecksum)
diff --git a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs
index 1bb740910dc6d..2befbad3917ba 100644
--- a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs
+++ b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ErrorReporting;
@@ -15,32 +16,20 @@ namespace Microsoft.CodeAnalysis.Remote
{
#region FindReferences
- internal class SerializableFindReferencesSearchOptions
+ [DataContract]
+ internal sealed class SerializableSymbolAndProjectId
{
- public bool AssociatePropertyReferencesWithSpecificAccessor;
- public bool Cascade;
+ [DataMember(Order = 0)]
+ public readonly string SymbolKeyData;
- public static SerializableFindReferencesSearchOptions Dehydrate(FindReferencesSearchOptions options)
- {
- return new SerializableFindReferencesSearchOptions
- {
- AssociatePropertyReferencesWithSpecificAccessor = options.AssociatePropertyReferencesWithSpecificAccessor,
- Cascade = options.Cascade,
- };
- }
+ [DataMember(Order = 1)]
+ public readonly ProjectId ProjectId;
- public FindReferencesSearchOptions Rehydrate()
+ public SerializableSymbolAndProjectId(string symbolKeyData, ProjectId projectId)
{
- return new FindReferencesSearchOptions(
- associatePropertyReferencesWithSpecificAccessor: AssociatePropertyReferencesWithSpecificAccessor,
- cascade: Cascade);
+ SymbolKeyData = symbolKeyData;
+ ProjectId = projectId;
}
- }
-
- internal class SerializableSymbolAndProjectId
- {
- public string SymbolKeyData;
- public ProjectId ProjectId;
public static SerializableSymbolAndProjectId Dehydrate(
IAliasSymbol alias, Document document, CancellationToken cancellationToken)
@@ -60,11 +49,7 @@ public static SerializableSymbolAndProjectId Dehydrate(
}
public static SerializableSymbolAndProjectId Create(ISymbol symbol, Project project, CancellationToken cancellationToken)
- => new SerializableSymbolAndProjectId
- {
- SymbolKeyData = symbol.GetSymbolKey(cancellationToken).ToString(),
- ProjectId = project.Id,
- };
+ => new(symbol.GetSymbolKey(cancellationToken).ToString(), project.Id);
public static bool TryCreate(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
@@ -90,11 +75,7 @@ public static bool TryCreate(
return false;
}
- result = new SerializableSymbolAndProjectId
- {
- SymbolKeyData = SymbolKey.CreateString(symbol, cancellationToken),
- ProjectId = project.Id,
- };
+ result = new SerializableSymbolAndProjectId(SymbolKey.CreateString(symbol, cancellationToken), project.Id);
return true;
}
public async Task TryRehydrateAsync(
@@ -126,83 +107,59 @@ public async Task TryRehydrateAsync(
}
}
- internal class SerializableSymbolUsageInfo : IEquatable
+ [DataContract]
+ internal readonly struct SerializableReferenceLocation
{
- public bool IsValueUsageInfo;
- public int UsageInfoUnderlyingValue;
-
- public static SerializableSymbolUsageInfo Dehydrate(SymbolUsageInfo symbolUsageInfo)
- {
- bool isValueUsageInfo;
- int usageInfoUnderlyingValue;
- if (symbolUsageInfo.ValueUsageInfoOpt.HasValue)
- {
- isValueUsageInfo = true;
- usageInfoUnderlyingValue = (int)symbolUsageInfo.ValueUsageInfoOpt.Value;
- }
- else
- {
- isValueUsageInfo = false;
- usageInfoUnderlyingValue = (int)symbolUsageInfo.TypeOrNamespaceUsageInfoOpt.Value;
- }
-
- return new SerializableSymbolUsageInfo
- {
- IsValueUsageInfo = isValueUsageInfo,
- UsageInfoUnderlyingValue = usageInfoUnderlyingValue
- };
- }
+ [DataMember(Order = 0)]
+ public readonly DocumentId Document;
- public SymbolUsageInfo Rehydrate()
- {
- return IsValueUsageInfo
- ? SymbolUsageInfo.Create((ValueUsageInfo)UsageInfoUnderlyingValue)
- : SymbolUsageInfo.Create((TypeOrNamespaceUsageInfo)UsageInfoUnderlyingValue);
- }
+ [DataMember(Order = 1)]
+ public readonly SerializableSymbolAndProjectId Alias;
- public bool Equals(SerializableSymbolUsageInfo other)
- {
- return other != null &&
- IsValueUsageInfo == other.IsValueUsageInfo &&
- UsageInfoUnderlyingValue == other.UsageInfoUnderlyingValue;
- }
+ [DataMember(Order = 2)]
+ public readonly TextSpan Location;
- public override bool Equals(object obj)
- => Equals(obj as SerializableSymbolUsageInfo);
+ [DataMember(Order = 3)]
+ public readonly bool IsImplicit;
- public override int GetHashCode()
- => Hash.Combine(IsValueUsageInfo.GetHashCode(), UsageInfoUnderlyingValue.GetHashCode());
- }
+ [DataMember(Order = 4)]
+ public readonly SymbolUsageInfo SymbolUsageInfo;
- internal class SerializableReferenceLocation
- {
- public DocumentId Document { get; set; }
+ [DataMember(Order = 5)]
+ public readonly ImmutableDictionary AdditionalProperties;
- public SerializableSymbolAndProjectId Alias { get; set; }
+ [DataMember(Order = 6)]
+ public readonly CandidateReason CandidateReason;
- public TextSpan Location { get; set; }
-
- public bool IsImplicit { get; set; }
-
- public SerializableSymbolUsageInfo SymbolUsageInfo { get; set; }
-
- public ImmutableDictionary AdditionalProperties { get; set; }
-
- public CandidateReason CandidateReason { get; set; }
+ public SerializableReferenceLocation(
+ DocumentId document,
+ SerializableSymbolAndProjectId alias,
+ TextSpan location,
+ bool isImplicit,
+ SymbolUsageInfo symbolUsageInfo,
+ ImmutableDictionary additionalProperties,
+ CandidateReason candidateReason)
+ {
+ Document = document;
+ Alias = alias;
+ Location = location;
+ IsImplicit = isImplicit;
+ SymbolUsageInfo = symbolUsageInfo;
+ AdditionalProperties = additionalProperties;
+ CandidateReason = candidateReason;
+ }
public static SerializableReferenceLocation Dehydrate(
ReferenceLocation referenceLocation, CancellationToken cancellationToken)
{
- return new SerializableReferenceLocation
- {
- Document = referenceLocation.Document.Id,
- Alias = SerializableSymbolAndProjectId.Dehydrate(referenceLocation.Alias, referenceLocation.Document, cancellationToken),
- Location = referenceLocation.Location.SourceSpan,
- IsImplicit = referenceLocation.IsImplicit,
- SymbolUsageInfo = SerializableSymbolUsageInfo.Dehydrate(referenceLocation.SymbolUsageInfo),
- AdditionalProperties = referenceLocation.AdditionalProperties,
- CandidateReason = referenceLocation.CandidateReason
- };
+ return new SerializableReferenceLocation(
+ referenceLocation.Document.Id,
+ SerializableSymbolAndProjectId.Dehydrate(referenceLocation.Alias, referenceLocation.Document, cancellationToken),
+ referenceLocation.Location.SourceSpan,
+ referenceLocation.IsImplicit,
+ referenceLocation.SymbolUsageInfo,
+ referenceLocation.AdditionalProperties,
+ referenceLocation.CandidateReason);
}
public async Task RehydrateAsync(
@@ -217,7 +174,7 @@ public async Task RehydrateAsync(
aliasSymbol,
CodeAnalysis.Location.Create(syntaxTree, Location),
isImplicit: IsImplicit,
- symbolUsageInfo: SymbolUsageInfo.Rehydrate(),
+ symbolUsageInfo: SymbolUsageInfo,
additionalProperties: additionalProperties ?? ImmutableDictionary.Empty,
candidateReason: CandidateReason);
}
diff --git a/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs b/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs
index ca4092ad760e7..51955fcac88c5 100644
--- a/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs
+++ b/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs
@@ -50,10 +50,6 @@ public string ToString(bool isRemoteHost64Bit)
{
(WellKnownServiceHubService.RemoteHost, false) => Prefix + nameof(WellKnownServiceHubService.RemoteHost),
(WellKnownServiceHubService.RemoteHost, true) => Prefix + nameof(WellKnownServiceHubService.RemoteHost) + Suffix64,
- (WellKnownServiceHubService.CodeAnalysis, false) => Prefix + nameof(WellKnownServiceHubService.CodeAnalysis),
- (WellKnownServiceHubService.CodeAnalysis, true) => Prefix + nameof(WellKnownServiceHubService.CodeAnalysis) + Suffix64,
- (WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, false) => Prefix + nameof(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine),
- (WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, true) => Prefix + nameof(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine) + Suffix64,
(WellKnownServiceHubService.LanguageServer, false) => Prefix + nameof(WellKnownServiceHubService.LanguageServer),
(WellKnownServiceHubService.LanguageServer, true) => Prefix + nameof(WellKnownServiceHubService.LanguageServer) + Suffix64,
diff --git a/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs b/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs
index 6397763589adc..69667ac1e81c5 100644
--- a/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs
+++ b/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -17,12 +18,12 @@ internal static class RemoteUtilities
/// the set of document text changes necessary to convert to .
///
- public static async Task<(DocumentId, TextChange[])[]> GetDocumentTextChangesAsync(
+ public static async ValueTask)>> GetDocumentTextChangesAsync(
Solution oldSolution,
Solution newSolution,
CancellationToken cancellationToken)
{
- using var _ = ArrayBuilder<(DocumentId, TextChange[])>.GetInstance(out var builder);
+ using var _ = ArrayBuilder<(DocumentId, ImmutableArray)>.GetInstance(out var builder);
var solutionChanges = newSolution.GetChanges(oldSolution);
foreach (var projectChange in solutionChanges.GetProjectChanges())
@@ -32,11 +33,11 @@ internal static class RemoteUtilities
var oldDoc = oldSolution.GetDocument(docId);
var newDoc = newSolution.GetDocument(docId);
var textChanges = await newDoc.GetTextChangesAsync(oldDoc, cancellationToken).ConfigureAwait(false);
- builder.Add((docId, textChanges.ToArray()));
+ builder.Add((docId, textChanges.ToImmutableArray()));
}
}
- return builder.ToArray();
+ return builder.ToImmutable();
}
///
@@ -44,7 +45,7 @@ internal static class RemoteUtilities
/// a solution textually equivalent to the newSolution passed to .
///
public static async Task UpdateSolutionAsync(
- Solution oldSolution, (DocumentId, TextChange[])[] documentTextChanges, CancellationToken cancellationToken)
+ Solution oldSolution, ImmutableArray<(DocumentId, ImmutableArray)> documentTextChanges, CancellationToken cancellationToken)
{
var currentSolution = oldSolution;
foreach (var (docId, textChanges) in documentTextChanges)
diff --git a/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs b/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs
index 787fd1e23f60d..d162ce804315f 100644
--- a/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs
+++ b/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs
@@ -10,8 +10,8 @@ internal enum WellKnownServiceHubService
{
None = 0,
RemoteHost = 1,
- CodeAnalysis = 2,
- RemoteSymbolSearchUpdateEngine = 3,
+ // obsolete: CodeAnalysis = 2,
+ // obsolete: RemoteSymbolSearchUpdateService = 3,
// obsolete: RemoteDesignerAttributeService = 4,
// obsolete: RemoteProjectTelemetryService = 5,
// obsolete: RemoteTodoCommentsService = 6,
diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs
index 25dfd69e333ca..a807d161e7a35 100644
--- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs
+++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs
@@ -3,14 +3,21 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Rename.ConflictEngine
{
+ [DataContract]
internal readonly struct ComplexifiedSpan
{
+ [DataMember(Order = 0)]
public readonly TextSpan OriginalSpan;
+
+ [DataMember(Order = 1)]
public readonly TextSpan NewSpan;
+
+ [DataMember(Order = 2)]
public readonly ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)> ModifiedSubSpans;
public ComplexifiedSpan(TextSpan originalSpan, TextSpan newSpan, ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)> modifiedSubSpans)
diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
index be0f2f98c4695..3e69d9e7aad5d 100644
--- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
+++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
@@ -52,21 +52,19 @@ internal static async Task ResolveConflictsAsync(
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteRenamer.ResolveConflictsAsync),
+ var serializableLocationSet = renameLocationSet.Dehydrate(solution, cancellationToken);
+ var nonConflictSymbolIds = nonConflictSymbols?.SelectAsArray(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)) ?? default;
+
+ var result = await client.TryInvokeAsync(
solution,
- new object?[]
- {
- renameLocationSet.Dehydrate(solution, cancellationToken),
- replacementText,
- nonConflictSymbols?.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(),
- },
+ (service, solutionInfo, cancellationToken) => service.ResolveConflictsAsync(solutionInfo, serializableLocationSet, replacementText, nonConflictSymbolIds, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- if (result != null)
- return await result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
+ if (result.HasValue && result.Value != null)
+ return await result.Value.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
+
+ // TODO: do not fall back to in-proc if client is available (https://github.com/dotnet/roslyn/issues/47557)
}
}
diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs
index 6474f170706af..29a5b5c52d530 100644
--- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs
+++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Rename.ConflictEngine
@@ -11,30 +12,39 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine
///
/// Gives information about an identifier span that was affected by Rename (Reference or Non reference)
///
+ [DataContract]
internal readonly struct RelatedLocation : IEquatable
{
///
/// The Span of the original identifier if it was in source, otherwise the span to check for implicit
/// references.
///
+ [DataMember(Order = 0)]
public readonly TextSpan ConflictCheckSpan;
+
+ [DataMember(Order = 1)]
+ public readonly DocumentId DocumentId;
+
+ [DataMember(Order = 2)]
public readonly RelatedLocationType Type;
+
+ [DataMember(Order = 3)]
public readonly bool IsReference;
- public readonly DocumentId DocumentId;
///
/// If there was a conflict at ConflictCheckSpan during rename, then the next phase in rename uses
/// ComplexifiedTargetSpan span to be expanded to resolve the conflict.
///
+ [DataMember(Order = 4)]
public readonly TextSpan ComplexifiedTargetSpan;
public RelatedLocation(TextSpan conflictCheckSpan, DocumentId documentId, RelatedLocationType type, bool isReference = false, TextSpan complexifiedTargetSpan = default)
{
- this.ConflictCheckSpan = conflictCheckSpan;
- this.Type = type;
- this.IsReference = isReference;
- this.DocumentId = documentId;
- this.ComplexifiedTargetSpan = complexifiedTargetSpan;
+ ConflictCheckSpan = conflictCheckSpan;
+ Type = type;
+ IsReference = isReference;
+ DocumentId = documentId;
+ ComplexifiedTargetSpan = complexifiedTargetSpan;
}
public RelatedLocation WithType(RelatedLocationType type)
diff --git a/src/Workspaces/Core/Portable/Rename/IRemoteRenamer.cs b/src/Workspaces/Core/Portable/Rename/IRemoteRenamer.cs
deleted file mode 100644
index bc907c60a8921..0000000000000
--- a/src/Workspaces/Core/Portable/Rename/IRemoteRenamer.cs
+++ /dev/null
@@ -1,300 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#nullable enable
-
-using System.Collections.Immutable;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.FindSymbols;
-using Microsoft.CodeAnalysis.PooledObjects;
-using Microsoft.CodeAnalysis.Remote;
-using Microsoft.CodeAnalysis.Rename.ConflictEngine;
-using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.Text;
-using Roslyn.Utilities;
-
-namespace Microsoft.CodeAnalysis.Rename
-{
- internal interface IRemoteRenamer
- {
- ///
- /// Runs the entire rename operation OOP and returns the final result. More efficient (due to less back and
- /// forth marshaling) when the intermediary results of rename are not needed. To get the individual parts of
- /// rename remoted use and .
- ///
- Task RenameSymbolAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId symbolAndProjectId,
- string replacementText,
- SerializableRenameOptionSet options,
- SerializableSymbolAndProjectId[] nonConflictSymbolIds,
- CancellationToken cancellationToken);
-
- Task FindRenameLocationsAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableSymbolAndProjectId symbolAndProjectId,
- SerializableRenameOptionSet options,
- CancellationToken cancellationToken);
-
- Task ResolveConflictsAsync(
- PinnedSolutionInfo solutionInfo,
- SerializableRenameLocations renameLocationSet,
- string replacementText,
- SerializableSymbolAndProjectId[] nonConflictSymbolIds,
- CancellationToken cancellationToken);
- }
-
- internal struct SerializableRenameOptionSet
- {
- public bool RenameOverloads;
- public bool RenameInStrings;
- public bool RenameInComments;
- public bool RenameFile;
-
- public static SerializableRenameOptionSet Dehydrate(RenameOptionSet optionSet)
- => new SerializableRenameOptionSet
- {
- RenameOverloads = optionSet.RenameOverloads,
- RenameInStrings = optionSet.RenameInStrings,
- RenameInComments = optionSet.RenameInComments,
- RenameFile = optionSet.RenameFile,
- };
-
- public RenameOptionSet Rehydrate()
- => new RenameOptionSet(RenameOverloads, RenameInStrings, RenameInComments, RenameFile);
- }
-
- internal class SerializableSearchResult
- {
- // We use arrays so we can represent default immutable arrays.
-
- public SerializableRenameLocation[]? Locations;
- public SerializableReferenceLocation[]? ImplicitLocations;
- public SerializableSymbolAndProjectId[]? ReferencedSymbols;
-
- [return: NotNullIfNotNull("result")]
- public static SerializableSearchResult? Dehydrate(Solution solution, RenameLocations.SearchResult? result, CancellationToken cancellationToken)
- => result == null ? null : new SerializableSearchResult
- {
- Locations = result.Locations.Select(loc => SerializableRenameLocation.Dehydrate(loc)).ToArray(),
- ImplicitLocations = result.ImplicitLocations.IsDefault ? null : result.ImplicitLocations.Select(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)).ToArray(),
- ReferencedSymbols = result.ReferencedSymbols.IsDefault ? null : result.ReferencedSymbols.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(),
- };
-
- public async Task RehydrateAsync(Solution solution, CancellationToken cancellationToken)
- {
- ImmutableArray implicitLocations = default;
- ImmutableArray referencedSymbols = default;
-
- Contract.ThrowIfNull(Locations);
-
- using var _1 = ArrayBuilder.GetInstance(Locations.Length, out var locBuilder);
- foreach (var loc in Locations)
- locBuilder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
-
- var locations = locBuilder.ToImmutableHashSet();
-
- if (ImplicitLocations != null)
- {
- using var _2 = ArrayBuilder.GetInstance(ImplicitLocations.Length, out var builder);
- foreach (var loc in ImplicitLocations)
- builder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
-
- implicitLocations = builder.ToImmutable();
- }
-
- if (ReferencedSymbols != null)
- {
- using var _3 = ArrayBuilder.GetInstance(ReferencedSymbols.Length, out var builder);
- foreach (var symbol in ReferencedSymbols)
- builder.AddIfNotNull(await symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
-
- referencedSymbols = builder.ToImmutable();
- }
-
- return new RenameLocations.SearchResult(locations, implicitLocations, referencedSymbols);
- }
- }
-
- internal struct SerializableRenameLocation
- {
- public TextSpan Location;
- public DocumentId DocumentId;
- public CandidateReason CandidateReason;
- public bool IsRenamableAliasUsage;
- public bool IsRenamableAccessor;
- public TextSpan ContainingLocationForStringOrComment;
- public bool IsWrittenTo;
-
- public static SerializableRenameLocation Dehydrate(RenameLocation location)
- => new SerializableRenameLocation
- {
- Location = location.Location.SourceSpan,
- DocumentId = location.DocumentId,
- CandidateReason = location.CandidateReason,
- IsRenamableAliasUsage = location.IsRenamableAliasUsage,
- IsRenamableAccessor = location.IsRenamableAccessor,
- ContainingLocationForStringOrComment = location.ContainingLocationForStringOrComment,
- IsWrittenTo = location.IsWrittenTo,
- };
-
- public async Task RehydrateAsync(Solution solution, CancellationToken cancellation)
- {
- var document = solution.GetRequiredDocument(DocumentId);
- var tree = await document.GetRequiredSyntaxTreeAsync(cancellation).ConfigureAwait(false);
-
- return new RenameLocation(
- CodeAnalysis.Location.Create(tree, Location),
- DocumentId,
- CandidateReason,
- IsRenamableAliasUsage,
- IsRenamableAccessor,
- IsWrittenTo,
- ContainingLocationForStringOrComment);
- }
- }
-
- internal partial class RenameLocations
- {
- public SerializableRenameLocations Dehydrate(Solution solution, CancellationToken cancellationToken)
- => new SerializableRenameLocations
- {
- Symbol = SerializableSymbolAndProjectId.Dehydrate(solution, Symbol, cancellationToken),
- Options = SerializableRenameOptionSet.Dehydrate(Options),
- Result = SerializableSearchResult.Dehydrate(solution, _result, cancellationToken),
- };
-
- internal static async Task TryRehydrateAsync(Solution solution, SerializableRenameLocations locations, CancellationToken cancellationToken)
- {
- if (locations == null)
- return null;
-
- if (locations.Symbol == null)
- return null;
-
- var symbol = await locations.Symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
- if (symbol == null)
- return null;
-
- Contract.ThrowIfNull(locations.Result);
-
- return new RenameLocations(
- symbol,
- solution,
- locations.Options.Rehydrate(),
- await locations.Result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
- }
- }
-
- internal class SerializableRenameLocations
- {
- public SerializableSymbolAndProjectId? Symbol;
- public SerializableRenameOptionSet Options;
- public SerializableSearchResult? Result;
- }
-
- internal class SerializableComplexifiedSpan
- {
- public TextSpan OriginalSpan;
- public TextSpan NewSpan;
- public ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)> ModifiedSubSpans;
-
- public ComplexifiedSpan Rehydrate()
- => new ComplexifiedSpan(OriginalSpan, NewSpan, ModifiedSubSpans);
-
- public static SerializableComplexifiedSpan Dehydrate(ComplexifiedSpan span)
- => new SerializableComplexifiedSpan
- {
- OriginalSpan = span.OriginalSpan,
- NewSpan = span.NewSpan,
- ModifiedSubSpans = span.ModifiedSubSpans,
- };
- }
-
- internal class SerializableRelatedLocation
- {
- public TextSpan ConflictCheckSpan;
- public RelatedLocationType Type;
- public bool IsReference;
- public DocumentId? DocumentId;
- public TextSpan ComplexifiedTargetSpan;
-
- public RelatedLocation Rehydrate()
- => new RelatedLocation(ConflictCheckSpan, DocumentId, Type, IsReference, ComplexifiedTargetSpan);
-
- public static SerializableRelatedLocation Dehydrate(RelatedLocation location)
- => new SerializableRelatedLocation
- {
- ConflictCheckSpan = location.ConflictCheckSpan,
- Type = location.Type,
- IsReference = location.IsReference,
- DocumentId = location.DocumentId,
- ComplexifiedTargetSpan = location.ComplexifiedTargetSpan,
- };
- }
-
- internal class SerializableConflictResolution
- {
- public string? ErrorMessage;
-
- public bool ReplacementTextValid;
-
- public (DocumentId documentId, string newName) RenamedDocument;
-
- // Note: arrays are used (instead of ImmutableArray) as jsonrpc can't marshal null values to/from those types.
- //
- // We also flatten dictionaries into key/value tuples because jsonrpc only supports dictionaries with string keys.
-
- public DocumentId[]? DocumentIds;
- public SerializableRelatedLocation[]? RelatedLocations;
- public (DocumentId, TextChange[])[]? DocumentTextChanges;
- public (DocumentId, ImmutableArray<(TextSpan oldSpan, TextSpan newSpan)>)[]? DocumentToModifiedSpansMap;
- public (DocumentId, ImmutableArray)[]? DocumentToComplexifiedSpansMap;
- public (DocumentId, ImmutableArray)[]? DocumentToRelatedLocationsMap;
-
- public async Task RehydrateAsync(Solution oldSolution, CancellationToken cancellationToken)
- {
- if (ErrorMessage != null)
- return new ConflictResolution(ErrorMessage);
-
- var newSolutionWithoutRenamedDocument = await RemoteUtilities.UpdateSolutionAsync(
- oldSolution, DocumentTextChanges, cancellationToken).ConfigureAwait(false);
- return new ConflictResolution(
- oldSolution,
- newSolutionWithoutRenamedDocument,
- ReplacementTextValid,
- RenamedDocument,
- DocumentIds.ToImmutableArrayOrEmpty(),
- RelatedLocations.SelectAsArray(loc => loc.Rehydrate()),
- DocumentToModifiedSpansMap.ToImmutableDictionaryOrEmpty(t => t.Item1, t => t.Item2),
- DocumentToComplexifiedSpansMap.ToImmutableDictionaryOrEmpty(t => t.Item1, t => t.Item2.SelectAsArray(c => c.Rehydrate())),
- DocumentToRelatedLocationsMap.ToImmutableDictionaryOrEmpty(t => t.Item1, t => t.Item2.SelectAsArray(c => c.Rehydrate())));
- }
- }
-
- internal partial struct ConflictResolution
- {
- public async Task DehydrateAsync(CancellationToken cancellationToken)
- {
- if (ErrorMessage != null)
- return new SerializableConflictResolution { ErrorMessage = ErrorMessage };
-
- var documentTextChanges = await RemoteUtilities.GetDocumentTextChangesAsync(OldSolution, _newSolutionWithoutRenamedDocument, cancellationToken).ConfigureAwait(false);
- return new SerializableConflictResolution
- {
- ReplacementTextValid = ReplacementTextValid,
- RenamedDocument = _renamedDocument,
- DocumentIds = DocumentIds.ToArray(),
- RelatedLocations = RelatedLocations.Select(loc => SerializableRelatedLocation.Dehydrate(loc)).ToArray(),
- DocumentTextChanges = documentTextChanges,
- DocumentToModifiedSpansMap = _documentToModifiedSpansMap.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
- DocumentToComplexifiedSpansMap = _documentToComplexifiedSpansMap.Select(kvp => (kvp.Key, kvp.Value.SelectAsArray(s => SerializableComplexifiedSpan.Dehydrate(s)))).ToArray(),
- DocumentToRelatedLocationsMap = _documentToRelatedLocationsMap.Select(kvp => (kvp.Key, kvp.Value.SelectAsArray(s => SerializableRelatedLocation.Dehydrate(s)))).ToArray(),
- };
- }
- }
-}
diff --git a/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs b/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs
new file mode 100644
index 0000000000000..8141d4047fbe6
--- /dev/null
+++ b/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs
@@ -0,0 +1,367 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.FindSymbols;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Rename.ConflictEngine;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Rename
+{
+ internal interface IRemoteRenamerService
+ {
+ ///
+ /// Runs the entire rename operation OOP and returns the final result. More efficient (due to less back and
+ /// forth marshaling) when the intermediary results of rename are not needed. To get the individual parts of
+ /// rename remoted use and .
+ ///
+ ValueTask RenameSymbolAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectId,
+ string replacementText,
+ SerializableRenameOptionSet options,
+ ImmutableArray nonConflictSymbolIds,
+ CancellationToken cancellationToken);
+
+ ValueTask FindRenameLocationsAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectId,
+ SerializableRenameOptionSet options,
+ CancellationToken cancellationToken);
+
+ ValueTask ResolveConflictsAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableRenameLocations renameLocationSet,
+ string replacementText,
+ ImmutableArray nonConflictSymbolIds,
+ CancellationToken cancellationToken);
+ }
+
+ [DataContract]
+ internal readonly struct SerializableRenameOptionSet
+ {
+ [DataMember(Order = 0)]
+ public readonly bool RenameOverloads;
+
+ [DataMember(Order = 1)]
+ public readonly bool RenameInStrings;
+
+ [DataMember(Order = 2)]
+ public readonly bool RenameInComments;
+
+ [DataMember(Order = 3)]
+ public readonly bool RenameFile;
+
+ public SerializableRenameOptionSet(bool renameOverloads, bool renameInStrings, bool renameInComments, bool renameFile)
+ {
+ RenameOverloads = renameOverloads;
+ RenameInStrings = renameInStrings;
+ RenameInComments = renameInComments;
+ RenameFile = renameFile;
+ }
+
+ public static SerializableRenameOptionSet Dehydrate(RenameOptionSet optionSet)
+ => new(renameOverloads: optionSet.RenameOverloads,
+ renameInStrings: optionSet.RenameInStrings,
+ renameInComments: optionSet.RenameInComments,
+ renameFile: optionSet.RenameFile);
+
+ public RenameOptionSet Rehydrate()
+ => new(RenameOverloads, RenameInStrings, RenameInComments, RenameFile);
+ }
+
+ [DataContract]
+ internal class SerializableSearchResult
+ {
+ // We use arrays so we can represent default immutable arrays.
+
+ [DataMember(Order = 0)]
+ public SerializableRenameLocation[]? Locations;
+
+ [DataMember(Order = 1)]
+ public SerializableReferenceLocation[]? ImplicitLocations;
+
+ [DataMember(Order = 2)]
+ public SerializableSymbolAndProjectId[]? ReferencedSymbols;
+
+ [return: NotNullIfNotNull("result")]
+ public static SerializableSearchResult? Dehydrate(Solution solution, RenameLocations.SearchResult? result, CancellationToken cancellationToken)
+ => result == null ? null : new SerializableSearchResult
+ {
+ Locations = result.Locations.Select(loc => SerializableRenameLocation.Dehydrate(loc)).ToArray(),
+ ImplicitLocations = result.ImplicitLocations.IsDefault ? null : result.ImplicitLocations.Select(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)).ToArray(),
+ ReferencedSymbols = result.ReferencedSymbols.IsDefault ? null : result.ReferencedSymbols.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(),
+ };
+
+ public async Task RehydrateAsync(Solution solution, CancellationToken cancellationToken)
+ {
+ ImmutableArray implicitLocations = default;
+ ImmutableArray referencedSymbols = default;
+
+ Contract.ThrowIfNull(Locations);
+
+ using var _1 = ArrayBuilder.GetInstance(Locations.Length, out var locBuilder);
+ foreach (var loc in Locations)
+ locBuilder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
+
+ var locations = locBuilder.ToImmutableHashSet();
+
+ if (ImplicitLocations != null)
+ {
+ using var _2 = ArrayBuilder.GetInstance(ImplicitLocations.Length, out var builder);
+ foreach (var loc in ImplicitLocations)
+ builder.Add(await loc.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
+
+ implicitLocations = builder.ToImmutable();
+ }
+
+ if (ReferencedSymbols != null)
+ {
+ using var _3 = ArrayBuilder.GetInstance(ReferencedSymbols.Length, out var builder);
+ foreach (var symbol in ReferencedSymbols)
+ builder.AddIfNotNull(await symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
+
+ referencedSymbols = builder.ToImmutable();
+ }
+
+ return new RenameLocations.SearchResult(locations, implicitLocations, referencedSymbols);
+ }
+ }
+
+ [DataContract]
+ internal readonly struct SerializableRenameLocation
+ {
+ [DataMember(Order = 0)]
+ public readonly TextSpan Location;
+
+ [DataMember(Order = 1)]
+ public readonly DocumentId DocumentId;
+
+ [DataMember(Order = 2)]
+ public readonly CandidateReason CandidateReason;
+
+ [DataMember(Order = 3)]
+ public readonly bool IsRenamableAliasUsage;
+
+ [DataMember(Order = 4)]
+ public readonly bool IsRenamableAccessor;
+
+ [DataMember(Order = 5)]
+ public readonly TextSpan ContainingLocationForStringOrComment;
+
+ [DataMember(Order = 6)]
+ public readonly bool IsWrittenTo;
+
+ public SerializableRenameLocation(
+ TextSpan location,
+ DocumentId documentId,
+ CandidateReason candidateReason,
+ bool isRenamableAliasUsage,
+ bool isRenamableAccessor,
+ TextSpan containingLocationForStringOrComment,
+ bool isWrittenTo)
+ {
+ Location = location;
+ DocumentId = documentId;
+ CandidateReason = candidateReason;
+ IsRenamableAliasUsage = isRenamableAliasUsage;
+ IsRenamableAccessor = isRenamableAccessor;
+ ContainingLocationForStringOrComment = containingLocationForStringOrComment;
+ IsWrittenTo = isWrittenTo;
+ }
+
+ public static SerializableRenameLocation Dehydrate(RenameLocation location)
+ => new(location.Location.SourceSpan,
+ location.DocumentId,
+ location.CandidateReason,
+ location.IsRenamableAliasUsage,
+ location.IsRenamableAccessor,
+ location.ContainingLocationForStringOrComment,
+ location.IsWrittenTo);
+
+ public async Task RehydrateAsync(Solution solution, CancellationToken cancellation)
+ {
+ var document = solution.GetRequiredDocument(DocumentId);
+ var tree = await document.GetRequiredSyntaxTreeAsync(cancellation).ConfigureAwait(false);
+
+ return new RenameLocation(
+ CodeAnalysis.Location.Create(tree, Location),
+ DocumentId,
+ CandidateReason,
+ IsRenamableAliasUsage,
+ IsRenamableAccessor,
+ IsWrittenTo,
+ ContainingLocationForStringOrComment);
+ }
+ }
+
+ internal partial class RenameLocations
+ {
+ public SerializableRenameLocations Dehydrate(Solution solution, CancellationToken cancellationToken)
+ => new SerializableRenameLocations(
+ SerializableSymbolAndProjectId.Dehydrate(solution, Symbol, cancellationToken),
+ SerializableRenameOptionSet.Dehydrate(Options),
+ SerializableSearchResult.Dehydrate(solution, _result, cancellationToken));
+
+ internal static async Task TryRehydrateAsync(Solution solution, SerializableRenameLocations locations, CancellationToken cancellationToken)
+ {
+ if (locations == null)
+ return null;
+
+ if (locations.Symbol == null)
+ return null;
+
+ var symbol = await locations.Symbol.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
+ if (symbol == null)
+ return null;
+
+ Contract.ThrowIfNull(locations.Result);
+
+ return new RenameLocations(
+ symbol,
+ solution,
+ locations.Options.Rehydrate(),
+ await locations.Result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false));
+ }
+ }
+
+ [DataContract]
+ internal sealed class SerializableRenameLocations
+ {
+ [DataMember(Order = 0)]
+ public readonly SerializableSymbolAndProjectId? Symbol;
+
+ [DataMember(Order = 1)]
+ public readonly SerializableRenameOptionSet Options;
+
+ [DataMember(Order = 2)]
+ public readonly SerializableSearchResult? Result;
+
+ public SerializableRenameLocations(SerializableSymbolAndProjectId? symbol, SerializableRenameOptionSet options, SerializableSearchResult? result)
+ {
+ Symbol = symbol;
+ Options = options;
+ Result = result;
+ }
+ }
+
+ [DataContract]
+ internal sealed class SerializableConflictResolution
+ {
+ [DataMember(Order = 0)]
+ public readonly string? ErrorMessage;
+
+ [DataMember(Order = 1)]
+ public readonly SuccessfulConflictResolution? Resolution;
+
+ public SerializableConflictResolution(string? errorMessage, SuccessfulConflictResolution? resolution)
+ {
+ ErrorMessage = errorMessage;
+ Resolution = resolution;
+ }
+
+ public async Task RehydrateAsync(Solution oldSolution, CancellationToken cancellationToken)
+ {
+ if (ErrorMessage != null)
+ return new ConflictResolution(ErrorMessage);
+
+ Contract.ThrowIfNull(Resolution);
+
+ var newSolutionWithoutRenamedDocument = await RemoteUtilities.UpdateSolutionAsync(
+ oldSolution, Resolution.DocumentTextChanges, cancellationToken).ConfigureAwait(false);
+
+ return new ConflictResolution(
+ oldSolution,
+ newSolutionWithoutRenamedDocument,
+ Resolution.ReplacementTextValid,
+ Resolution.RenamedDocument,
+ Resolution.DocumentIds,
+ Resolution.RelatedLocations,
+ Resolution.DocumentToModifiedSpansMap,
+ Resolution.DocumentToComplexifiedSpansMap,
+ Resolution.DocumentToRelatedLocationsMap);
+ }
+ }
+
+ [DataContract]
+ internal sealed class SuccessfulConflictResolution
+ {
+ [DataMember(Order = 0)]
+ public readonly bool ReplacementTextValid;
+
+ [DataMember(Order = 1)]
+ public readonly (DocumentId documentId, string newName) RenamedDocument;
+
+ [DataMember(Order = 2)]
+ public readonly ImmutableArray DocumentIds;
+
+ [DataMember(Order = 3)]
+ public readonly ImmutableArray RelatedLocations;
+
+ [DataMember(Order = 4)]
+ public readonly ImmutableArray<(DocumentId, ImmutableArray)> DocumentTextChanges;
+
+ [DataMember(Order = 5)]
+ public readonly ImmutableDictionary> DocumentToModifiedSpansMap;
+
+ [DataMember(Order = 6)]
+ public readonly ImmutableDictionary> DocumentToComplexifiedSpansMap;
+
+ [DataMember(Order = 7)]
+ public readonly ImmutableDictionary> DocumentToRelatedLocationsMap;
+
+ public SuccessfulConflictResolution(
+ bool replacementTextValid,
+ (DocumentId documentId, string newName) renamedDocument,
+ ImmutableArray documentIds,
+ ImmutableArray relatedLocations,
+ ImmutableArray<(DocumentId, ImmutableArray)> documentTextChanges,
+ ImmutableDictionary> documentToModifiedSpansMap,
+ ImmutableDictionary> documentToComplexifiedSpansMap,
+ ImmutableDictionary> documentToRelatedLocationsMap)
+ {
+ ReplacementTextValid = replacementTextValid;
+ RenamedDocument = renamedDocument;
+ DocumentIds = documentIds;
+ RelatedLocations = relatedLocations;
+ DocumentTextChanges = documentTextChanges;
+ DocumentToModifiedSpansMap = documentToModifiedSpansMap;
+ DocumentToComplexifiedSpansMap = documentToComplexifiedSpansMap;
+ DocumentToRelatedLocationsMap = documentToRelatedLocationsMap;
+ }
+ }
+
+ internal partial struct ConflictResolution
+ {
+ public async Task DehydrateAsync(CancellationToken cancellationToken)
+ {
+ if (ErrorMessage != null)
+ return new SerializableConflictResolution(ErrorMessage, resolution: null);
+
+ var documentTextChanges = await RemoteUtilities.GetDocumentTextChangesAsync(OldSolution, _newSolutionWithoutRenamedDocument, cancellationToken).ConfigureAwait(false);
+ return new SerializableConflictResolution(
+ errorMessage: null,
+ new SuccessfulConflictResolution(
+ ReplacementTextValid,
+ _renamedDocument,
+ DocumentIds,
+ RelatedLocations,
+ documentTextChanges,
+ _documentToModifiedSpansMap,
+ _documentToComplexifiedSpansMap,
+ _documentToRelatedLocationsMap));
+ }
+ }
+}
diff --git a/src/Workspaces/Core/Portable/Rename/RenameLocations.cs b/src/Workspaces/Core/Portable/Rename/RenameLocations.cs
index 2c1ece38c04ab..d8f46cdcf6e01 100644
--- a/src/Workspaces/Core/Portable/Rename/RenameLocations.cs
+++ b/src/Workspaces/Core/Portable/Rename/RenameLocations.cs
@@ -62,47 +62,6 @@ internal static RenameLocations Create(
new SearchResult(locations, implicitLocations, referencedSymbols));
}
- private static RenameLocations Create(
- ISymbol symbol,
- Solution solution,
- RenameOptionSet options,
- SearchResult originalSymbolResult,
- ImmutableArray overloadsResult,
- ImmutableArray stringsResult,
- ImmutableArray commentsResult)
- {
- var mergedLocations = ImmutableHashSet.CreateBuilder();
- using var _1 = ArrayBuilder.GetInstance(out var mergedReferencedSymbols);
- using var _2 = ArrayBuilder.GetInstance(out var mergedImplicitLocations);
-
- if (options.RenameInStrings)
- mergedLocations.AddRange(stringsResult);
-
- if (options.RenameInComments)
- mergedLocations.AddRange(commentsResult);
-
- var renameMethodGroupReferences = options.RenameOverloads || !GetOverloadedSymbols(symbol).Any();
- var overloadsToMerge = options.RenameOverloads
- ? overloadsResult.NullToEmpty()
- : ImmutableArray.Empty;
- foreach (var result in overloadsToMerge.Concat(originalSymbolResult))
- {
- mergedLocations.AddRange(renameMethodGroupReferences
- ? result.Locations
- : result.Locations.Where(x => x.CandidateReason != CandidateReason.MemberGroup));
-
- mergedImplicitLocations.AddRange(result.ImplicitLocations);
- mergedReferencedSymbols.AddRange(result.ReferencedSymbols);
- }
-
- return new RenameLocations(
- symbol, solution, options,
- new SearchResult(
- mergedLocations.ToImmutable(),
- mergedImplicitLocations.ToImmutable(),
- mergedReferencedSymbols.ToImmutable()));
- }
-
///
/// Find the locations that need to be renamed.
///
@@ -121,26 +80,24 @@ public static async Task FindLocationsAsync(
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteRenamer.FindRenameLocationsAsync),
+ var options = SerializableRenameOptionSet.Dehydrate(optionSet);
+
+ var result = await client.TryInvokeAsync(
solution,
- new object[]
- {
- serializedSymbol,
- SerializableRenameOptionSet.Dehydrate(optionSet),
- },
+ (service, solutionInfo, cancellationToken) => service.FindRenameLocationsAsync(solutionInfo, serializedSymbol, options, cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- if (result != null)
+ if (result.HasValue && result.Value != null)
{
- var rehydrated = await RenameLocations.TryRehydrateAsync(
- solution, result, cancellationToken).ConfigureAwait(false);
+ var rehydrated = await TryRehydrateAsync(
+ solution, result.Value, cancellationToken).ConfigureAwait(false);
if (rehydrated != null)
return rehydrated;
}
+
+ // TODO: do not fall back to in-proc if client is available (https://github.com/dotnet/roslyn/issues/47557)
}
}
}
diff --git a/src/Workspaces/Core/Portable/Rename/Renamer.cs b/src/Workspaces/Core/Portable/Rename/Renamer.cs
index 9af151b77fc0d..c192cf019736c 100644
--- a/src/Workspaces/Core/Portable/Rename/Renamer.cs
+++ b/src/Workspaces/Core/Portable/Rename/Renamer.cs
@@ -127,22 +127,25 @@ internal static async Task RenameSymbolAsync(
var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
if (client != null)
{
- var result = await client.RunRemoteAsync(
- WellKnownServiceHubService.CodeAnalysis,
- nameof(IRemoteRenamer.RenameSymbolAsync),
+ var options = SerializableRenameOptionSet.Dehydrate(optionSet);
+ var nonConflictSymbolIds = nonConflictSymbols?.SelectAsArray(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)) ?? default;
+
+ var result = await client.TryInvokeAsync(
solution,
- new object?[]
- {
+ (service, solutionInfo, cancellationToken) => service.RenameSymbolAsync(
+ solutionInfo,
serializedSymbol,
newName,
- SerializableRenameOptionSet.Dehydrate(optionSet),
- nonConflictSymbols?.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(),
- },
+ options,
+ nonConflictSymbolIds,
+ cancellationToken),
callbackTarget: null,
cancellationToken).ConfigureAwait(false);
- if (result != null)
- return await result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
+ if (result.HasValue && result.Value != null)
+ return await result.Value.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false);
+
+ // TODO: do not fall back to in-proc if client is available (https://github.com/dotnet/roslyn/issues/47557)
}
}
}
diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs
index 37088d4b1609e..cea0381877f5e 100644
--- a/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs
+++ b/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs
@@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
{
internal interface IStreamingProgressTracker
{
- Task AddItemsAsync(int count);
- Task ItemCompletedAsync();
+ ValueTask AddItemsAsync(int count);
+ ValueTask ItemCompletedAsync();
}
}
diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs
index 7e4be62ec4407..ec673f6cc912f 100644
--- a/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs
+++ b/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.Threading;
using System.Threading.Tasks;
@@ -11,41 +13,36 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
///
/// Utility class that can be used to track the progress of an operation in a threadsafe manner.
///
- internal class StreamingProgressTracker : IStreamingProgressTracker
+ internal sealed class StreamingProgressTracker : IStreamingProgressTracker
{
private int _completedItems;
private int _totalItems;
- private readonly Func _updateActionOpt;
-
- public StreamingProgressTracker()
- : this(null)
- {
- }
+ private readonly Func? _updateAction;
- public StreamingProgressTracker(Func updateActionOpt)
- => _updateActionOpt = updateActionOpt;
+ public StreamingProgressTracker(Func? updateAction = null)
+ => _updateAction = updateAction;
- public Task AddItemsAsync(int count)
+ public ValueTask AddItemsAsync(int count)
{
Interlocked.Add(ref _totalItems, count);
return UpdateAsync();
}
- public Task ItemCompletedAsync()
+ public ValueTask ItemCompletedAsync()
{
Interlocked.Increment(ref _completedItems);
return UpdateAsync();
}
- private Task UpdateAsync()
+ private ValueTask UpdateAsync()
{
- if (_updateActionOpt == null)
+ if (_updateAction == null)
{
- return Task.CompletedTask;
+ return default;
}
- return _updateActionOpt(_completedItems, _totalItems);
+ return _updateAction(_completedItems, _totalItems);
}
}
}
diff --git a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs
index 09255a5cfd178..88a3c952e654d 100644
--- a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs
+++ b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs
@@ -2,18 +2,17 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.SymbolSearch
{
- internal interface IRemoteSymbolSearchUpdateEngine
+ internal interface IRemoteSymbolSearchUpdateService
{
- Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory);
-
- Task> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken);
- Task> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken);
- Task> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken);
+ ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken);
+ ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken);
+ ValueTask> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken);
+ ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken);
}
}
diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs
index bfe34a21e5f1a..93fffce2ead10 100644
--- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs
+++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.SymbolSearch
@@ -11,7 +12,7 @@ namespace Microsoft.CodeAnalysis.SymbolSearch
///
internal interface ISymbolSearchLogService
{
- Task LogExceptionAsync(string exception, string text);
- Task LogInfoAsync(string text);
+ ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken);
+ ValueTask LogInfoAsync(string text, CancellationToken cancellationToken);
}
}
diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs
index 30c959949d02e..5f1404a7ac876 100644
--- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs
+++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs
@@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
+using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
@@ -27,7 +28,7 @@ internal interface ISymbolSearchService : IWorkspaceService
/// Implementations should return results in order from best to worst (from their
/// perspective).
///
- Task> FindPackagesWithTypeAsync(
+ ValueTask> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken);
///
@@ -38,7 +39,7 @@ Task> FindPackagesWithTypeAsync(
/// Implementations should return results in order from best to worst (from their
/// perspective).
///
- Task> FindPackagesWithAssemblyAsync(
+ ValueTask> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken);
///
@@ -50,14 +51,18 @@ Task> FindPackagesWithAssemblyAsync(
/// Implementations should return results in order from best to worst (from their
/// perspective).
///
- Task> FindReferenceAssembliesWithTypeAsync(
+ ValueTask> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken);
}
+ [DataContract]
internal abstract class PackageResult
{
+ [DataMember(Order = 0)]
public readonly string PackageName;
- internal readonly int Rank;
+
+ [DataMember(Order = 1)]
+ public readonly int Rank;
protected PackageResult(string packageName, int rank)
{
@@ -66,37 +71,45 @@ protected PackageResult(string packageName, int rank)
}
}
- internal class PackageWithTypeResult : PackageResult
+ [DataContract]
+ internal sealed class PackageWithTypeResult : PackageResult
{
- public readonly IList ContainingNamespaceNames;
+ [DataMember(Order = 2)]
public readonly string TypeName;
+
+ [DataMember(Order = 3)]
public readonly string? Version;
+ [DataMember(Order = 4)]
+ public readonly ImmutableArray ContainingNamespaceNames;
+
public PackageWithTypeResult(
string packageName,
- string typeName,
- string version,
int rank,
- IList containingNamespaceNames)
+ string typeName,
+ string? version,
+ ImmutableArray containingNamespaceNames)
: base(packageName, rank)
{
TypeName = typeName;
- Version = string.IsNullOrWhiteSpace(version) ? null : version;
+ Version = version;
ContainingNamespaceNames = containingNamespaceNames;
}
}
- internal class PackageWithAssemblyResult : PackageResult, IEquatable, IComparable
+ [DataContract]
+ internal sealed class PackageWithAssemblyResult : PackageResult, IEquatable, IComparable
{
+ [DataMember(Order = 2)]
public readonly string? Version;
public PackageWithAssemblyResult(
string packageName,
- string version,
- int rank)
+ int rank,
+ string version)
: base(packageName, rank)
{
- Version = string.IsNullOrWhiteSpace(version) ? null : version;
+ Version = version;
}
public override int GetHashCode()
@@ -120,16 +133,22 @@ public int CompareTo(PackageWithAssemblyResult? other)
ImmutableArray.Create>(p => p.Rank, p => p.PackageName);
}
- internal class ReferenceAssemblyWithTypeResult
+ [DataContract]
+ internal sealed class ReferenceAssemblyWithTypeResult
{
- public readonly IList ContainingNamespaceNames;
+ [DataMember(Order = 0)]
public readonly string AssemblyName;
+
+ [DataMember(Order = 1)]
public readonly string TypeName;
+ [DataMember(Order = 2)]
+ public readonly ImmutableArray ContainingNamespaceNames;
+
public ReferenceAssemblyWithTypeResult(
string assemblyName,
string typeName,
- IList containingNamespaceNames)
+ ImmutableArray containingNamespaceNames)
{
AssemblyName = assemblyName;
TypeName = typeName;
@@ -146,22 +165,13 @@ public DefaultSymbolSearchService()
{
}
- public Task> FindPackagesWithTypeAsync(
- string source, string name, int arity, CancellationToken cancellationToken)
- {
- return SpecializedTasks.EmptyList();
- }
+ public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
- public Task> FindPackagesWithAssemblyAsync(
- string source, string assemblyName, CancellationToken cancellationToken)
- {
- return SpecializedTasks.EmptyList();
- }
+ public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
- public Task> FindReferenceAssembliesWithTypeAsync(
- string name, int arity, CancellationToken cancellationToken)
- {
- return SpecializedTasks.EmptyList();
- }
+ public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken)
+ => new(ImmutableArray.Empty);
}
}
diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs
index 4d7bf2db34729..e7891ed6388ef 100644
--- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs
+++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs
@@ -14,13 +14,13 @@ namespace Microsoft.CodeAnalysis.SymbolSearch
///
internal interface ISymbolSearchUpdateEngine
{
- Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory);
+ ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken);
- Task> FindPackagesWithTypeAsync(
+ ValueTask> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken);
- Task> FindPackagesWithAssemblyAsync(
+ ValueTask> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken);
- Task> FindReferenceAssembliesWithTypeAsync(
+ ValueTask> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken);
}
}
diff --git a/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs b/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
index 286a07b2b063c..cf26b2e2c049d 100644
--- a/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
+++ b/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs
@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.TodoComments
/// Interface to allow host (VS) to inform the OOP service to start incrementally analyzing and
/// reporting results back to the host.
///
- internal interface IRemoteTodoCommentsService
+ internal interface IRemoteTodoCommentsDiscoveryService
{
ValueTask ComputeTodoCommentsAsync(CancellationToken cancellation);
}
diff --git a/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs b/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs
index afc80298a0588..2676e24bba86a 100644
--- a/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs
+++ b/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs
@@ -5,6 +5,7 @@
#nullable enable
using System;
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
@@ -13,17 +14,48 @@ namespace Microsoft.CodeAnalysis.TodoComments
///
/// Serialization type used to pass information to/from OOP and VS.
///
- internal struct TodoCommentData : IEquatable
+ [DataContract]
+ internal readonly struct TodoCommentData : IEquatable
{
- public int Priority;
- public string Message;
- public DocumentId DocumentId;
- public string? MappedFilePath;
- public string? OriginalFilePath;
- public int MappedLine;
- public int MappedColumn;
- public int OriginalLine;
- public int OriginalColumn;
+ [DataMember(Order = 0)]
+ public readonly int Priority;
+
+ [DataMember(Order = 1)]
+ public readonly string Message;
+
+ [DataMember(Order = 2)]
+ public readonly DocumentId DocumentId;
+
+ [DataMember(Order = 3)]
+ public readonly string? MappedFilePath;
+
+ [DataMember(Order = 4)]
+ public readonly string? OriginalFilePath;
+
+ [DataMember(Order = 5)]
+ public readonly int MappedLine;
+
+ [DataMember(Order = 6)]
+ public readonly int MappedColumn;
+
+ [DataMember(Order = 7)]
+ public readonly int OriginalLine;
+
+ [DataMember(Order = 8)]
+ public readonly int OriginalColumn;
+
+ public TodoCommentData(int priority, string message, DocumentId documentId, string? mappedFilePath, string? originalFilePath, int mappedLine, int mappedColumn, int originalLine, int originalColumn)
+ {
+ Priority = priority;
+ Message = message;
+ DocumentId = documentId;
+ MappedFilePath = mappedFilePath;
+ OriginalFilePath = originalFilePath;
+ MappedLine = mappedLine;
+ MappedColumn = mappedColumn;
+ OriginalLine = originalLine;
+ OriginalColumn = originalColumn;
+ }
public override bool Equals(object? obj)
=> obj is TodoCommentData other && Equals(other);
@@ -32,16 +64,14 @@ public override int GetHashCode()
=> GetHashCode(this);
public override string ToString()
- => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine.ToString()}, {MappedColumn.ToString()}) [original: {OriginalFilePath ?? ""} ({OriginalLine.ToString()}, {OriginalColumn.ToString()})";
+ => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine}, {MappedColumn}) [original: {OriginalFilePath ?? ""} ({OriginalLine}, {OriginalColumn})";
public bool Equals(TodoCommentData right)
- {
- return DocumentId == right.DocumentId &&
- Priority == right.Priority &&
- Message == right.Message &&
- OriginalLine == right.OriginalLine &&
- OriginalColumn == right.OriginalColumn;
- }
+ => DocumentId == right.DocumentId &&
+ Priority == right.Priority &&
+ Message == right.Message &&
+ OriginalLine == right.OriginalLine &&
+ OriginalColumn == right.OriginalColumn;
public static int GetHashCode(TodoCommentData item)
=> Hash.Combine(item.DocumentId,
@@ -64,19 +94,14 @@ internal void WriteTo(ObjectWriter writer)
}
internal static TodoCommentData ReadFrom(ObjectReader reader)
- {
- return new TodoCommentData
- {
- Priority = reader.ReadInt32(),
- Message = reader.ReadString(),
- DocumentId = DocumentId.ReadFrom(reader),
- MappedFilePath = reader.ReadString(),
- OriginalFilePath = reader.ReadString(),
- MappedLine = reader.ReadInt32(),
- MappedColumn = reader.ReadInt32(),
- OriginalLine = reader.ReadInt32(),
- OriginalColumn = reader.ReadInt32(),
- };
- }
+ => new(priority: reader.ReadInt32(),
+ message: reader.ReadString(),
+ documentId: DocumentId.ReadFrom(reader),
+ mappedFilePath: reader.ReadString(),
+ originalFilePath: reader.ReadString(),
+ mappedLine: reader.ReadInt32(),
+ mappedColumn: reader.ReadInt32(),
+ originalLine: reader.ReadInt32(),
+ originalColumn: reader.ReadInt32());
}
}
diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs
index ead29c303e77d..b7a29f8c918ec 100644
--- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.PersistentStorage
@@ -29,26 +30,34 @@ public DocumentKey(ProjectKey project, DocumentId id, string filePath, string na
}
public static explicit operator DocumentKey(Document document)
- => new DocumentKey((ProjectKey)document.Project, document.Id, document.FilePath, document.Name);
+ => new((ProjectKey)document.Project, document.Id, document.FilePath, document.Name);
public SerializableDocumentKey Dehydrate()
- {
- return new SerializableDocumentKey
- {
- Project = Project.Dehydrate(),
- Id = Id,
- FilePath = FilePath,
- Name = Name,
- };
- }
+ => new(Project.Dehydrate(), Id, FilePath, Name);
}
- internal class SerializableDocumentKey
+ [DataContract]
+ internal readonly struct SerializableDocumentKey
{
- public SerializableProjectKey Project;
- public DocumentId Id;
- public string FilePath;
- public string Name;
+ [DataMember(Order = 0)]
+ public readonly SerializableProjectKey Project;
+
+ [DataMember(Order = 1)]
+ public readonly DocumentId Id;
+
+ [DataMember(Order = 2)]
+ public readonly string FilePath;
+
+ [DataMember(Order = 3)]
+ public readonly string Name;
+
+ public SerializableDocumentKey(SerializableProjectKey project, DocumentId id, string filePath, string name)
+ {
+ Project = project;
+ Id = id;
+ FilePath = filePath;
+ Name = name;
+ }
public DocumentKey Rehydrate()
=> new DocumentKey(Project.Rehydrate(), Id, FilePath, Name);
diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs
index 680d1d244c257..5d81d2ad19f65 100644
--- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.PersistentStorage
@@ -29,28 +30,36 @@ public ProjectKey(SolutionKey solution, ProjectId id, string filePath, string na
}
public static explicit operator ProjectKey(Project project)
- => new ProjectKey((SolutionKey)project.Solution, project.Id, project.FilePath, project.Name);
+ => new((SolutionKey)project.Solution, project.Id, project.FilePath, project.Name);
public SerializableProjectKey Dehydrate()
- {
- return new SerializableProjectKey
- {
- Solution = Solution.Dehydrate(),
- Id = Id,
- FilePath = FilePath,
- Name = Name,
- };
- }
+ => new(Solution.Dehydrate(), Id, FilePath, Name);
}
- internal class SerializableProjectKey
+ [DataContract]
+ internal readonly struct SerializableProjectKey
{
- public SerializableSolutionKey Solution;
- public ProjectId Id;
- public string FilePath;
- public string Name;
+ [DataMember(Order = 0)]
+ public readonly SerializableSolutionKey Solution;
+
+ [DataMember(Order = 1)]
+ public readonly ProjectId Id;
+
+ [DataMember(Order = 2)]
+ public readonly string FilePath;
+
+ [DataMember(Order = 3)]
+ public readonly string Name;
+
+ public SerializableProjectKey(SerializableSolutionKey solution, ProjectId id, string filePath, string name)
+ {
+ Solution = solution;
+ Id = id;
+ FilePath = filePath;
+ Name = name;
+ }
public ProjectKey Rehydrate()
- => new ProjectKey(Solution.Rehydrate(), Id, FilePath, Name);
+ => new(Solution.Rehydrate(), Id, FilePath, Name);
}
}
diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs
index f2569e7ac0eb1..9bd8ba8b09c10 100644
--- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.Serialization;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.PersistentStorage
@@ -26,26 +27,32 @@ public SolutionKey(SolutionId id, string filePath, bool isPrimaryBranch)
}
public static explicit operator SolutionKey(Solution solution)
- => new SolutionKey(solution.Id, solution.FilePath, solution.BranchId == solution.Workspace.PrimaryBranchId);
+ => new(solution.Id, solution.FilePath, solution.BranchId == solution.Workspace.PrimaryBranchId);
public SerializableSolutionKey Dehydrate()
- {
- return new SerializableSolutionKey
- {
- Id = Id,
- FilePath = FilePath,
- IsPrimaryBranch = IsPrimaryBranch,
- };
- }
+ => new(Id, FilePath, IsPrimaryBranch);
}
- internal class SerializableSolutionKey
+ [DataContract]
+ internal readonly struct SerializableSolutionKey
{
- public SolutionId Id;
- public string FilePath;
- public bool IsPrimaryBranch;
+ [DataMember(Order = 0)]
+ public readonly SolutionId Id;
+
+ [DataMember(Order = 1)]
+ public readonly string FilePath;
+
+ [DataMember(Order = 2)]
+ public readonly bool IsPrimaryBranch;
+
+ public SerializableSolutionKey(SolutionId id, string filePath, bool isPrimaryBranch)
+ {
+ Id = id;
+ FilePath = filePath;
+ IsPrimaryBranch = isPrimaryBranch;
+ }
public SolutionKey Rehydrate()
- => new SolutionKey(Id, FilePath, IsPrimaryBranch);
+ => new(Id, FilePath, IsPrimaryBranch);
}
}
diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs
index b81b7662ee16d..0f5d07ac7aa2f 100644
--- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs
@@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
@@ -15,6 +16,7 @@ namespace Microsoft.CodeAnalysis
/// Checksum of data can be used later to see whether two data are same or not
/// without actually comparing data itself
///
+ [DataContract]
internal sealed partial class Checksum : IObjectWritable, IEquatable
{
///
@@ -24,8 +26,12 @@ internal sealed partial class Checksum : IObjectWritable, IEquatable
public static readonly Checksum Null = new Checksum(default);
+ [DataMember(Order = 0)]
private readonly HashData _checksum;
+ public Checksum(HashData hash)
+ => _checksum = hash;
+
///
/// Create Checksum from given byte array. if byte array is bigger than
/// , it will be truncated to the size
@@ -95,9 +101,6 @@ private static unsafe Checksum FromWorker(byte[] checksum)
}
}
- private Checksum(HashData hash)
- => _checksum = hash;
-
public bool Equals(Checksum other)
{
if (other == null)
@@ -149,17 +152,25 @@ public static string GetChecksumsLogInfo(IEnumerable checksums)
/// This structure stores the 20-byte hash as an inline value rather than requiring the use of
/// byte[].
///
+ [DataContract]
[StructLayout(LayoutKind.Explicit, Size = HashSize)]
- private struct HashData : IEquatable
+ public readonly struct HashData : IEquatable
{
- [FieldOffset(0)]
- private long Data1;
+ [FieldOffset(0), DataMember(Order = 0)]
+ private readonly long Data1;
- [FieldOffset(8)]
- private long Data2;
+ [FieldOffset(8), DataMember(Order = 1)]
+ private readonly long Data2;
- [FieldOffset(16)]
- private int Data3;
+ [FieldOffset(16), DataMember(Order = 2)]
+ private readonly int Data3;
+
+ public HashData(long data1, long data2, int data3)
+ {
+ Data1 = data1;
+ Data2 = data2;
+ Data3 = data3;
+ }
public static bool operator ==(HashData x, HashData y)
=> x.Equals(y);
@@ -175,22 +186,10 @@ public void WriteTo(ObjectWriter writer)
}
public static unsafe HashData FromPointer(HashData* hash)
- {
- HashData result = default;
- result.Data1 = hash->Data1;
- result.Data2 = hash->Data2;
- result.Data3 = hash->Data3;
- return result;
- }
+ => new(hash->Data1, hash->Data2, hash->Data3);
public static HashData ReadFrom(ObjectReader reader)
- {
- HashData result = default;
- result.Data1 = reader.ReadInt64();
- result.Data2 = reader.ReadInt64();
- result.Data3 = reader.ReadInt32();
- return result;
- }
+ => new(reader.ReadInt64(), reader.ReadInt64(), reader.ReadInt32());
public override int GetHashCode()
{
diff --git a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs
new file mode 100644
index 0000000000000..15df12c257f50
--- /dev/null
+++ b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs
@@ -0,0 +1,162 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using MessagePack;
+using Roslyn.Test.Utilities;
+using Roslyn.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Remote.UnitTests
+{
+ public class ServiceDescriptorTests
+ {
+ private static Dictionary GetAllParameterTypesOfRemoteApis()
+ {
+ var interfaces = new List();
+
+ foreach (var (serviceType, (descriptor, _)) in ServiceDescriptors.Descriptors)
+ {
+ interfaces.Add(serviceType);
+ if (descriptor.ClientInterface != null)
+ {
+ interfaces.Add(descriptor.ClientInterface);
+ }
+ }
+
+ var types = new Dictionary();
+
+ void AddTypeRecursive(Type type, MemberInfo declaringMember)
+ {
+ if (type.IsArray)
+ {
+ type = type.GetElementType();
+ }
+
+ if (types.ContainsKey(type))
+ {
+ return;
+ }
+
+ types.Add(type, declaringMember);
+
+ if (type.IsGenericType)
+ {
+ // Immutable collections and tuples have custom formatters which would fail during serialization if
+ // formatters were not available for the element types.
+ if (type.Namespace == typeof(ImmutableArray<>).Namespace ||
+ type.GetGenericTypeDefinition() == typeof(Nullable<>) ||
+ type.Namespace == "System" && type.Name.StartsWith("ValueTuple", StringComparison.Ordinal) ||
+ type.Namespace == "System" && type.Name.StartsWith("Tuple", StringComparison.Ordinal))
+ {
+ foreach (var genericArgument in type.GetGenericArguments())
+ {
+ AddTypeRecursive(genericArgument, declaringMember);
+ }
+ }
+ }
+
+ foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (field.GetCustomAttributes().Any())
+ {
+ AddTypeRecursive(field.FieldType, type);
+ }
+ }
+
+ foreach (var property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (property.GetCustomAttributes().Any())
+ {
+ AddTypeRecursive(property.PropertyType, type);
+ }
+ }
+ }
+
+ foreach (var interfaceType in interfaces)
+ {
+ foreach (var method in interfaceType.GetMethods())
+ {
+ if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
+ {
+ AddTypeRecursive(method.ReturnType.GetGenericArguments().Single(), method);
+ }
+ else
+ {
+ // remote API must return ValueTask or ValueTask
+ Assert.Equal(typeof(ValueTask), method.ReturnType);
+ }
+
+ foreach (var type in method.GetParameters().Select(p => p.ParameterType))
+ {
+ // stream is special cased by JSON-RPC for streaming APIs
+ if (type != typeof(Stream))
+ {
+ AddTypeRecursive(type, method);
+ }
+ }
+ }
+ }
+
+ types.Remove(typeof(CancellationToken));
+
+ return types;
+ }
+
+ [Fact]
+ public void TypesUsedInRemoteApisMustBeMessagePackSerializable()
+ {
+ var types = GetAllParameterTypesOfRemoteApis();
+ var resolver = ServiceDescriptor.TestAccessor.Options.Resolver;
+
+ var errors = new List();
+
+ foreach (var (type, declaringMember) in types)
+ {
+ try
+ {
+ if (resolver.GetFormatterDynamic(type) == null)
+ {
+ errors.Add($"{type} referenced by {declaringMember} is not serializable");
+ }
+ }
+ catch (Exception e)
+ {
+ // Known issues:
+ // Internal enums need a custom formatter: https://github.com/neuecc/MessagePack-CSharp/issues/1025
+ // This test fails with "... is attempting to implement an inaccessible interface." error message.
+ if (type.IsEnum && type.IsNotPublic ||
+ type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
+ type.GetGenericArguments().Single().IsEnum && type.GetGenericArguments().Single().IsNotPublic)
+ {
+ errors.Add($"{type} referenced by {declaringMember} is an internal enum and needs a custom formatter");
+ }
+ else
+ {
+ errors.Add($"{type} referenced by {declaringMember} failed to serialize with exception: {e}");
+ }
+ }
+ }
+
+ AssertEx.Empty(errors, "Types are not MessagePack-serializable");
+ }
+
+ [Fact]
+ public void GetFeatureName()
+ {
+ foreach (var (serviceType, _) in ServiceDescriptors.Descriptors)
+ {
+ Assert.NotEmpty(ServiceDescriptors.GetFeatureName(serviceType));
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/CoreTestUtilities/MEF/FeaturesTestCompositions.cs b/src/Workspaces/CoreTestUtilities/MEF/FeaturesTestCompositions.cs
index aaca36d050a8f..d0996fd7511fc 100644
--- a/src/Workspaces/CoreTestUtilities/MEF/FeaturesTestCompositions.cs
+++ b/src/Workspaces/CoreTestUtilities/MEF/FeaturesTestCompositions.cs
@@ -15,7 +15,9 @@ public static class FeaturesTestCompositions
{
public static readonly TestComposition Features = TestComposition.Empty
.AddAssemblies(MefHostServices.DefaultAssemblies)
- .AddParts(typeof(MockWorkspaceEventListenerProvider)); // by default, avoid running Solution Crawler and other services that start in workspace event listeners
+ .AddParts(
+ typeof(MockWorkspaceEventListenerProvider), // by default, avoid running Solution Crawler and other services that start in workspace event listeners
+ typeof(TestErrorReportingService)); // mocks the info-bar error reporting
public static readonly TestComposition RemoteHost = TestComposition.Empty
.AddAssemblies(RemoteWorkspaceManager.RemoteHostAssemblies);
diff --git a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs
index b263854dc6324..f22a39812ee6d 100644
--- a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs
+++ b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs
@@ -14,6 +14,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Experiments;
+using Microsoft.CodeAnalysis.Extensions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Serialization;
using Microsoft.CodeAnalysis.TodoComments;
@@ -120,7 +121,7 @@ public override async ValueTask> CreateConnectionAsyn
#pragma warning restore
Contract.ThrowIfNull(proxy);
- return new BrokeredServiceConnection(proxy, assetStorage, errorReportingService: null);
+ return new BrokeredServiceConnection(proxy, assetStorage, _workspaceServices.GetRequiredService(), shutdownCancellationService: null);
}
public override async Task CreateConnectionAsync(RemoteServiceName serviceName, object? callbackTarget, CancellationToken cancellationToken)
@@ -234,15 +235,26 @@ public InProcRemoteServices(HostWorkspaceServices workspaceServices, RemoteHostT
ServiceBroker = new InProcServiceBroker(this);
RegisterService(WellKnownServiceHubService.RemoteHost, (s, p, o) => new RemoteHostService(s, p));
- RegisterService(WellKnownServiceHubService.CodeAnalysis, (s, p, o) => new CodeAnalysisService(s, p));
- RegisterService(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, (s, p, o) => new RemoteSymbolSearchUpdateEngine(s, p));
RegisterInProcBrokeredService(SolutionAssetProvider.ServiceDescriptor, () => new SolutionAssetProvider(workspaceServices));
- RegisterRemoteBrokeredService(new RemoteDesignerAttributeService.Factory());
+ RegisterRemoteBrokeredService(new RemoteSymbolSearchUpdateService.Factory());
+ RegisterRemoteBrokeredService(new RemoteDesignerAttributeDiscoveryService.Factory());
RegisterRemoteBrokeredService(new RemoteProjectTelemetryService.Factory());
- RegisterRemoteBrokeredService(new RemoteTodoCommentsService.Factory());
+ RegisterRemoteBrokeredService(new RemoteTodoCommentsDiscoveryService.Factory());
RegisterRemoteBrokeredService(new RemoteDiagnosticAnalyzerService.Factory());
RegisterRemoteBrokeredService(new RemoteSemanticClassificationService.Factory());
RegisterRemoteBrokeredService(new RemoteSemanticClassificationCacheService.Factory());
+ RegisterRemoteBrokeredService(new RemoteDocumentHighlightsService.Factory());
+ RegisterRemoteBrokeredService(new RemoteEncapsulateFieldService.Factory());
+ RegisterRemoteBrokeredService(new RemoteRenamerService.Factory());
+ RegisterRemoteBrokeredService(new RemoteConvertTupleToStructCodeRefactoringService.Factory());
+ RegisterRemoteBrokeredService(new RemoteFindUsagesService.Factory());
+ RegisterRemoteBrokeredService(new RemoteSymbolFinderService.Factory());
+ RegisterRemoteBrokeredService(new RemoteNavigateToSearchService.Factory());
+ RegisterRemoteBrokeredService(new RemoteMissingImportDiscoveryService.Factory());
+ RegisterRemoteBrokeredService(new RemoteExtensionMethodImportCompletionService.Factory());
+ RegisterRemoteBrokeredService(new RemoteDependentTypeFinderService.Factory());
+ RegisterRemoteBrokeredService(new RemoteGlobalNotificationDeliveryService.Factory());
+ RegisterRemoteBrokeredService(new RemoteCodeLensReferencesService.Factory());
RegisterService(WellKnownServiceHubService.LanguageServer, (s, p, o) => new LanguageServer(s, p));
}
@@ -280,7 +292,7 @@ public object CreateBrokeredService(ServiceRpcDescriptor descriptor, IDuplexPipe
// Currently don't support callback creation as we don't have in-proc service with callbacks yet.
Contract.ThrowIfFalse(descriptor.ClientInterface == null);
- var serviceConnection = descriptor.ConstructRpcConnection(pipe);
+ var serviceConnection = descriptor.WithTraceSource(_serviceProvider.TraceSource).ConstructRpcConnection(pipe);
var service = inProcFactory();
serviceConnection.AddLocalRpcTarget(service);
diff --git a/src/Workspaces/CoreTestUtilities/TestErrorReportingService.cs b/src/Workspaces/CoreTestUtilities/TestErrorReportingService.cs
new file mode 100644
index 0000000000000..9b111d2befb25
--- /dev/null
+++ b/src/Workspaces/CoreTestUtilities/TestErrorReportingService.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#nullable enable
+
+using System;
+using System.Composition;
+using Microsoft.CodeAnalysis.Extensions;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Test.Utilities
+{
+ [ExportWorkspaceService(typeof(IErrorReportingService), ServiceLayer.Test), Shared]
+ internal sealed class TestErrorReportingService : IErrorReportingService
+ {
+ [ImportingConstructor]
+ [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+ public TestErrorReportingService()
+ {
+ }
+
+ public Action OnError { get; set; } = message => Assert.False(true, message);
+
+ public string HostDisplayName
+ => "Test Host";
+
+ public void ShowDetailedErrorInfo(Exception exception)
+ => OnError(exception.Message);
+
+ public void ShowErrorInfoInActiveView(string message, params InfoBarUI[] items)
+ => OnError(message);
+
+ public void ShowGlobalErrorInfo(string message, params InfoBarUI[] items)
+ => OnError(message);
+
+ public void ShowRemoteHostCrashedErrorInfo(Exception? exception)
+ => OnError(exception?.Message ?? "Unexpected error");
+
+ public void ShowFeatureNotAvailableErrorInfo(string message, Exception? exception)
+ => OnError($"{message} {exception}");
+ }
+}
diff --git a/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs b/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs
index 98ab8b399cc9d..15accfa6d8154 100644
--- a/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs
+++ b/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs
@@ -2,26 +2,40 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
+
using System;
using System.IO;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
+using MessagePack;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Extensions;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Internal.Log;
using Nerdbank.Streams;
+using StreamJsonRpc;
+using StreamJsonRpc.Protocol;
namespace Microsoft.CodeAnalysis.Remote
{
internal sealed class BrokeredServiceConnection : RemoteServiceConnection
where TService : class
{
- private readonly IErrorReportingService _errorReportingService;
+ private readonly IErrorReportingService? _errorReportingService;
+ private readonly IRemoteHostClientShutdownCancellationService? _shutdownCancellationService;
private readonly SolutionAssetStorage _solutionAssetStorage;
private readonly TService _service;
- public BrokeredServiceConnection(TService service, SolutionAssetStorage solutionAssetStorage, IErrorReportingService errorReportingService)
+ public BrokeredServiceConnection(
+ TService service,
+ SolutionAssetStorage solutionAssetStorage,
+ IErrorReportingService? errorReportingService,
+ IRemoteHostClientShutdownCancellationService? shutdownCancellationService)
{
_errorReportingService = errorReportingService;
+ _shutdownCancellationService = shutdownCancellationService;
_solutionAssetStorage = solutionAssetStorage;
_service = service;
}
@@ -38,7 +52,7 @@ public override async ValueTask TryInvokeAsync(Func> TryInvokeAsync(Func<
{
return await invocation(_service, cancellationToken).ConfigureAwait(false);
}
- catch (Exception exception) when (FatalError.ReportWithoutCrashUnlessCanceled(exception, cancellationToken))
+ catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken))
{
OnUnexpectedException(exception, cancellationToken);
return default;
@@ -67,7 +81,7 @@ public override async ValueTask> TryInvokeAsync(
{
return await InvokeStreamingServiceAsync(_service, invocation, reader, cancellationToken).ConfigureAwait(false);
}
- catch (Exception exception) when (FatalError.ReportWithoutCrashUnlessCanceled(exception, cancellationToken))
+ catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken))
{
OnUnexpectedException(exception, cancellationToken);
return default;
@@ -84,7 +98,7 @@ public override async ValueTask TryInvokeAsync(Solution solution, Func> TryInvokeAsync(Solut
using var scope = await _solutionAssetStorage.StoreAssetsAsync(solution, cancellationToken).ConfigureAwait(false);
return await invocation(_service, scope.SolutionInfo, cancellationToken).ConfigureAwait(false);
}
- catch (Exception exception) when (FatalError.ReportWithoutCrashUnlessCanceled(exception, cancellationToken))
+ catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken))
{
OnUnexpectedException(exception, cancellationToken);
return default;
@@ -120,7 +134,7 @@ public override async ValueTask> TryInvokeAsync(
reader,
cancellationToken).ConfigureAwait(false);
}
- catch (Exception exception) when (FatalError.ReportWithoutCrashUnlessCanceled(exception, cancellationToken))
+ catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken))
{
OnUnexpectedException(exception, cancellationToken);
return default;
@@ -147,18 +161,70 @@ internal static async ValueTask InvokeStreamingServiceAsync(
return readerTask.Result;
}
+ private bool ReportUnexpectedException(Exception exception, CancellationToken cancellationToken)
+ {
+ // Do not report telemetry when the host is shutting down or the remote service threw an IO exception:
+ if (IsHostShuttingDown || IsRemoteIOException(exception))
+ {
+ return true;
+ }
+
+ // report telemetry event:
+ Logger.Log(FunctionId.FeatureNotAvailable, $"{ServiceDescriptors.GetServiceName(typeof(TService))}: {exception.GetType()}: {exception.Message}");
+
+ return FatalError.ReportWithoutCrashUnlessCanceled(exception, cancellationToken);
+ }
+
+ private bool IsHostShuttingDown
+ => _shutdownCancellationService?.ShutdownToken.IsCancellationRequested == true;
+
+ // TODO: we need https://github.com/microsoft/vs-streamjsonrpc/issues/468 to be implemented in order to check for IOException subtypes.
+ private static bool IsRemoteIOException(Exception exception)
+ => exception is RemoteInvocationException { ErrorData: CommonErrorData { TypeName: "System.IO.IOException" } };
+
private void OnUnexpectedException(Exception exception, CancellationToken cancellationToken)
{
- // Remote call may fail with different exception even when our cancellation token is signaled
- // (e.g. on shutdown if the connection is dropped):
+ // If the cancellation token passed to the remote call is not linked with the host shutdown cancellation token,
+ // various non-cancellation exceptions may occur during the remote call.
+ // Throw cancellation exception if the cancellation token is signaled.
+ // If it is not then show info to the user that the service is not available dure to shutdown.
cancellationToken.ThrowIfCancellationRequested();
- // TODO: better message depending on the exception (https://github.com/dotnet/roslyn/issues/40476):
- // "Feature xyz is currently unavailable due to network issues" (connection exceptions)
- // "Feature xyz is currently unavailable due to an internal error [Details]" (exception is RemoteInvocationException, serialization issues)
- // "Feature xyz is currently unavailable" (connection exceptions during shutdown cancellation when cancellationToken is not signalled)
+ if (_errorReportingService == null)
+ {
+ return;
+ }
+
+ // Show the error on the client. See https://github.com/dotnet/roslyn/issues/40476 for error classification details.
+ // Based on the exception type and the state of the system we report one of the following:
+ // - "Feature xyz is currently unavailable due to an intermittent error. Please try again later. Error message: '{1}'" (RemoteInvocationException: IOException)
+ // - "Feature xyz is currently unavailable due to an internal error [Details]" (exception is RemoteInvocationException, MessagePackSerializationException, ConnectionLostException)
+ // - "Feature xyz is currently unavailable since Visual Studio is shutting down" (connection exceptions during shutdown cancellation when cancellationToken is not signalled)
+
+ // We expect all RPC calls to complete and not drop the connection.
+ // ConnectionLostException indicates a bug that is likely thrown because the remote process crashed.
+ // Currently, ConnectionLostException is also throw when the result of the RPC method fails to serialize
+ // (see https://github.com/microsoft/vs-streamjsonrpc/issues/549)
+
+ string message;
+ Exception? internalException = null;
+ var featureName = ServiceDescriptors.GetFeatureName(typeof(TService));
+
+ if (IsRemoteIOException(exception))
+ {
+ message = string.Format(RemoteWorkspacesResources.Feature_0_is_currently_unavailable_due_to_an_intermittent_error, featureName, exception.Message);
+ }
+ else if (IsHostShuttingDown)
+ {
+ message = string.Format(RemoteWorkspacesResources.Feature_0_is_currently_unavailable_host_shutting_down, featureName, _errorReportingService.HostDisplayName);
+ }
+ else
+ {
+ message = string.Format(RemoteWorkspacesResources.Feature_0_is_currently_unavailable_due_to_an_internal_error, featureName);
+ internalException = exception;
+ }
- _errorReportingService?.ShowRemoteHostCrashedErrorInfo(exception);
+ _errorReportingService.ShowFeatureNotAvailableErrorInfo(message, internalException);
}
}
}
diff --git a/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs b/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs
index a12b667038805..b31e6fe36cce4 100644
--- a/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs
+++ b/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs
@@ -94,11 +94,8 @@ private async Task SendStartNotificationAsync(Task(),
+ _ = await client.TryInvokeAsync(
+ (service, cancellationToken) => service.OnGlobalOperationStartedAsync(cancellationToken),
callbackTarget: null,
_cancellationToken).ConfigureAwait(false);
@@ -129,11 +126,8 @@ private async Task SendStoppedNotificationAsync(Task(
+ (service, cancellationToken) => service.OnGlobalOperationStoppedAsync(e.Operations, e.Cancelled, cancellationToken),
callbackTarget: null,
_cancellationToken).ConfigureAwait(false);
diff --git a/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs b/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs
index 33932ee12bb12..9fd47a3e1c8e4 100644
--- a/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs
+++ b/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs
@@ -5,13 +5,15 @@
#nullable enable
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Remote
{
internal interface IRemoteGlobalNotificationDeliveryService
{
- void OnGlobalOperationStarted();
+ ValueTask OnGlobalOperationStartedAsync(CancellationToken cancellationToken);
- void OnGlobalOperationStopped(IReadOnlyList operations, bool cancelled);
+ ValueTask OnGlobalOperationStoppedAsync(IReadOnlyList operations, bool cancelled, CancellationToken cancellationToken);
}
}
diff --git a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj
index 969e173ca909f..4bc5b43b3c16f 100644
--- a/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj
+++ b/src/Workspaces/Remote/Core/Microsoft.CodeAnalysis.Remote.Workspaces.csproj
@@ -34,6 +34,9 @@
+
+
+
diff --git a/src/Workspaces/Remote/Core/RemoteCallback.cs b/src/Workspaces/Remote/Core/RemoteCallback.cs
index 93a1569025f8b..941efd4404637 100644
--- a/src/Workspaces/Remote/Core/RemoteCallback.cs
+++ b/src/Workspaces/Remote/Core/RemoteCallback.cs
@@ -8,6 +8,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using MessagePack;
using Microsoft.CodeAnalysis.ErrorReporting;
using Nerdbank.Streams;
using Newtonsoft.Json;
@@ -78,45 +79,55 @@ public async ValueTask InvokeAsync(
}
}
- // TODO: https://github.com/microsoft/vs-streamjsonrpc/issues/246
+ // Remote calls can only throw 4 types of exceptions that correspond to
//
- // We need to get to a state when remote calls can only throw 4 types of exceptions that correspond to
// 1) Connection issue (connection dropped for any reason)
// 2) Serialization issue - bug in serialization of arguments (types are not serializable, etc.)
// 3) Remote exception - an exception was thrown by the callee
// 4) Cancelation
- // When a connection is dropped and CancelLocallyInvokedMethodsWhenConnectionIsClosed is set the connection dropped exception [1] should not be thrown.
- // Instead a the cancellation token should be signaled and OperationCancelledException should be thrown ([4]).
//
- // Until the above issue in JSON-RPC is fixed we do a best guess on what the issue is.
-
private bool ReportUnexpectedException(Exception exception, CancellationToken cancellationToken)
{
- if (exception is RemoteInvocationException or JsonException)
+ if (exception is IOException)
{
- // indicates bug on client side or in serialization, propagate the exception
- return FatalError.ReportWithoutCrashAndPropagate(exception);
+ // propagate intermittent exceptions without reporting telemetry:
+ return false;
}
- if (cancellationToken.IsCancellationRequested)
+ if (exception is OperationCanceledException)
{
- // If cancelation is requested and we see a different exception the handler will throw OperationCancelledException.
- return exception is not OperationCanceledException;
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return false;
+ }
+
+ // It is not guaranteed that RPC only throws OCE when our token is signaled.
+ // Signal the cancelation source that our token is linked to and throw new cancellation
+ // exception in OnUnexpectedException.
+ ClientDisconnectedSource.Cancel();
+
+ return true;
}
- // We assume that any other exception indicates lost connection (it might not),
- // cancel any ongoing work since the client can't receive the results.
- // This should be handled by JSON-RPC but it's not guaranteed due to https://github.com/microsoft/vs-streamjsonrpc/issues/246.
- ClientDisconnectedSource.Cancel();
+ // When a connection is dropped and CancelLocallyInvokedMethodsWhenConnectionIsClosed is
+ // set ConnectionLostException should not be thrown. Instead the cancellation token should be
+ // signaled and OperationCancelledException should be thrown.
+ // Seems to not work in all cases currently, so we need to cancel ourselves (bug https://github.com/microsoft/vs-streamjsonrpc/issues/551).
+ // Once this issue is fixed we can remov this if statement and fall back to reporting NFW
+ // as any observation of ConnectionLostException indicates a bug (e.g. https://github.com/microsoft/vs-streamjsonrpc/issues/549).
+ if (exception is ConnectionLostException)
+ {
+ ClientDisconnectedSource.Cancel();
+
+ return true;
+ }
- // catch the exception, cancellation exception will be thrown by the handler.
- return true;
+ // Indicates bug on client side or in serialization, report NFW and propagate the exception.
+ return FatalError.ReportWithoutCrashAndPropagate(exception);
}
private static Exception OnUnexpectedException(CancellationToken cancellationToken)
{
- // Remote call may fail with different exception even when our cancellation token is signaled
- // (e.g. on shutdown if the connection is dropped):
cancellationToken.ThrowIfCancellationRequested();
// If this is hit the cancellation token passed to the service implementation did not use the correct token.
diff --git a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.cs b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.cs
deleted file mode 100644
index fe0767a041a3d..0000000000000
--- a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.CodeAnalysis.Remote
-{
- ///
- /// Stub type - replace with type generated from resx file when resources are needed in this assembly.
- ///
- internal static class RemoteWorkspacesResources
- {
- }
-}
diff --git a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx
new file mode 100644
index 0000000000000..a7055d04205cf
--- /dev/null
+++ b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Feature '{0}' is currently unavailable since {1} is shutting down.
+
+
+ Feature '{0}' is currently unavailable due to an intermittent error, please try again later: '{1}'
+
+
+ Feature '{0}' is currently unavailable due to an internal error.
+
+
+ Missing import discovery
+
+
+ CodeLens references
+
+
+ Convert tuple to struct refactoring
+
+
+ Dependent type finder
+
+
+ DesignerAttribute discovery
+
+
+ Diagnostic analyzer runner
+
+
+ Document higlights
+
+
+ Encapsulate field refactoring
+
+
+ Extension method import completion
+
+
+ Find usages
+
+
+ Global notification delivery
+
+
+ Navigate to
+
+
+ Project telemetry collection
+
+
+ Rename
+
+
+ Semantic classification
+
+
+ Semantic classification cache
+
+
+ Symbol finder
+
+
+ Symbol search
+
+
+ TODO comments discovery
+
+
\ No newline at end of file
diff --git a/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs b/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs
new file mode 100644
index 0000000000000..7389dc20c37e6
--- /dev/null
+++ b/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs
@@ -0,0 +1,394 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Reflection;
+using MessagePack;
+using MessagePack.Formatters;
+
+// TODO: Copied from https://github.com/neuecc/MessagePack-CSharp/blob/master/src/MessagePack.ImmutableCollection/Formatters.cs.
+// Replace with an implementation shipping with VS:
+// https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1198374
+// https://github.com/neuecc/MessagePack-CSharp/issues/606
+//
+// The following code includes fix for: https://github.com/neuecc/MessagePack-CSharp/issues/1033. Make sure the fix is included in the replacement.
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ internal sealed class ImmutableCollectionMessagePackResolver : IFormatterResolver
+ {
+ public static readonly ImmutableCollectionMessagePackResolver Instance = new ImmutableCollectionMessagePackResolver();
+
+ private ImmutableCollectionMessagePackResolver()
+ {
+ }
+
+ public IMessagePackFormatter GetFormatter()
+ => FormatterCache.Formatter;
+
+ private static class FormatterCache
+ {
+ internal static readonly IMessagePackFormatter Formatter;
+
+ static FormatterCache()
+ {
+ Formatter = (IMessagePackFormatter)GetFormatter(typeof(T));
+ }
+ }
+
+ private static readonly Dictionary s_formatterMap = new Dictionary()
+ {
+ { typeof(ImmutableArray<>), typeof(ImmutableArrayFormatter<>) },
+ { typeof(ImmutableList<>), typeof(ImmutableListFormatter<>) },
+ { typeof(ImmutableDictionary<,>), typeof(ImmutableDictionaryFormatter<,>) },
+ { typeof(ImmutableHashSet<>), typeof(ImmutableHashSetFormatter<>) },
+ { typeof(ImmutableSortedDictionary<,>), typeof(ImmutableSortedDictionaryFormatter<,>) },
+ { typeof(ImmutableSortedSet<>), typeof(ImmutableSortedSetFormatter<>) },
+ { typeof(ImmutableQueue<>), typeof(ImmutableQueueFormatter<>) },
+ { typeof(ImmutableStack<>), typeof(ImmutableStackFormatter<>) },
+ { typeof(IImmutableList<>), typeof(InterfaceImmutableListFormatter<>) },
+ { typeof(IImmutableDictionary<,>), typeof(InterfaceImmutableDictionaryFormatter<,>) },
+ { typeof(IImmutableQueue<>), typeof(InterfaceImmutableQueueFormatter<>) },
+ { typeof(IImmutableSet<>), typeof(InterfaceImmutableSetFormatter<>) },
+ { typeof(IImmutableStack<>), typeof(InterfaceImmutableStackFormatter<>) },
+ };
+
+ internal static object GetFormatter(Type t)
+ {
+ var ti = t.GetTypeInfo();
+
+ if (ti.IsGenericType)
+ {
+ var genericType = ti.GetGenericTypeDefinition();
+ var genericTypeInfo = genericType.GetTypeInfo();
+ var isNullable = genericTypeInfo.IsGenericType && genericTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
+ var nullableElementType = isNullable ? ti.GenericTypeArguments[0] : null;
+
+ if (s_formatterMap.TryGetValue(genericType, out var formatterType))
+ {
+ return CreateInstance(formatterType, ti.GenericTypeArguments);
+ }
+
+ if (isNullable && nullableElementType.IsConstructedGenericType && nullableElementType.GetGenericTypeDefinition() == typeof(ImmutableArray<>))
+ {
+ return CreateInstance(typeof(NullableFormatter<>), new[] { nullableElementType });
+ }
+ }
+
+ return null;
+ }
+
+ private static object CreateInstance(Type genericType, Type[] genericTypeArguments, params object[] arguments)
+ => Activator.CreateInstance(genericType.MakeGenericType(genericTypeArguments), arguments);
+
+ // ImmutableArray.Enumerator is 'not' IEnumerator, can't use abstraction layer.
+ internal sealed class ImmutableArrayFormatter : IMessagePackFormatter>
+ {
+ public void Serialize(ref MessagePackWriter writer, ImmutableArray value, MessagePackSerializerOptions options)
+ {
+ if (value.IsDefault)
+ {
+ writer.WriteNil();
+ }
+ else
+ {
+ var formatter = options.Resolver.GetFormatterWithVerify();
+
+ writer.WriteArrayHeader(value.Length);
+
+ foreach (var item in value)
+ {
+ formatter.Serialize(ref writer, item, options);
+ }
+ }
+ }
+
+ public ImmutableArray Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
+ {
+ if (reader.TryReadNil())
+ {
+ return default;
+ }
+ else
+ {
+ var formatter = options.Resolver.GetFormatterWithVerify();
+
+ var len = reader.ReadArrayHeader();
+
+ var builder = ImmutableArray.CreateBuilder(len);
+ options.Security.DepthStep(ref reader);
+ try
+ {
+ for (var i = 0; i < len; i++)
+ {
+ builder.Add(formatter.Deserialize(ref reader, options));
+ }
+ }
+ finally
+ {
+ reader.Depth--;
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+ }
+
+ internal sealed class ImmutableListFormatter : CollectionFormatterBase.Builder, ImmutableList.Enumerator, ImmutableList>
+ {
+ protected override void Add(ImmutableList.Builder collection, int index, T value, MessagePackSerializerOptions options)
+ {
+ collection.Add(value);
+ }
+
+ protected override ImmutableList Complete(ImmutableList.Builder intermediateCollection)
+ {
+ return intermediateCollection.ToImmutable();
+ }
+
+ protected override ImmutableList.Builder Create(int count, MessagePackSerializerOptions options)
+ {
+ return ImmutableList.CreateBuilder();
+ }
+
+ protected override ImmutableList.Enumerator GetSourceEnumerator(ImmutableList source)
+ {
+ return source.GetEnumerator();
+ }
+ }
+
+ internal sealed class ImmutableDictionaryFormatter : DictionaryFormatterBase.Builder, ImmutableDictionary.Enumerator, ImmutableDictionary>
+ {
+ protected override void Add(ImmutableDictionary.Builder collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
+ {
+ collection.Add(key, value);
+ }
+
+ protected override ImmutableDictionary Complete(ImmutableDictionary.Builder intermediateCollection)
+ {
+ return intermediateCollection.ToImmutable();
+ }
+
+ protected override ImmutableDictionary.Builder Create(int count, MessagePackSerializerOptions options)
+ {
+ return ImmutableDictionary.CreateBuilder(options.Security.GetEqualityComparer());
+ }
+
+ protected override ImmutableDictionary.Enumerator GetSourceEnumerator(ImmutableDictionary source)
+ {
+ return source.GetEnumerator();
+ }
+ }
+
+ internal sealed class ImmutableHashSetFormatter : CollectionFormatterBase.Builder, ImmutableHashSet.Enumerator, ImmutableHashSet>
+ {
+ protected override void Add(ImmutableHashSet.Builder collection, int index, T value, MessagePackSerializerOptions options)
+ {
+ collection.Add(value);
+ }
+
+ protected override ImmutableHashSet Complete(ImmutableHashSet.Builder intermediateCollection)
+ {
+ return intermediateCollection.ToImmutable();
+ }
+
+ protected override ImmutableHashSet.Builder Create(int count, MessagePackSerializerOptions options)
+ {
+ return ImmutableHashSet.CreateBuilder