diff --git a/eng/targets/Services.props b/eng/targets/Services.props index 972b09b076ea1..20f7924e3e8f0 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -11,33 +11,12 @@ Note that brokered services must be defined in Microsoft.VisualStudio service namespace in order to be considered first party. --> + - - - - - - - - - - - - - - - - - - - + + + + - - - - - \ No newline at end of file diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs index 62eca7c0b1910..1e4968e80cc1d 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerTelemetry.cs @@ -5,136 +5,114 @@ #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. /// - [DataMember(Order = 0)] - public int CompilationStartActionsCount { get; set; } + public int CompilationStartActionsCount { get; set; } = 0; /// /// Count of registered compilation end actions. /// - [DataMember(Order = 1)] - public int CompilationEndActionsCount { get; set; } + public int CompilationEndActionsCount { get; set; } = 0; /// /// Count of registered compilation actions. /// - [DataMember(Order = 2)] - public int CompilationActionsCount { get; set; } + public int CompilationActionsCount { get; set; } = 0; /// /// Count of registered syntax tree actions. /// - [DataMember(Order = 3)] - public int SyntaxTreeActionsCount { get; set; } + public int SyntaxTreeActionsCount { get; set; } = 0; /// /// Count of registered additional file actions. /// - [DataMember(Order = 4)] - public int AdditionalFileActionsCount { get; set; } + public int AdditionalFileActionsCount { get; set; } = 0; /// /// Count of registered semantic model actions. /// - [DataMember(Order = 5)] - public int SemanticModelActionsCount { get; set; } + public int SemanticModelActionsCount { get; set; } = 0; /// /// Count of registered symbol actions. /// - [DataMember(Order = 6)] - public int SymbolActionsCount { get; set; } + public int SymbolActionsCount { get; set; } = 0; /// /// Count of registered symbol start actions. /// - [DataMember(Order = 7)] - public int SymbolStartActionsCount { get; set; } + public int SymbolStartActionsCount { get; set; } = 0; /// /// Count of registered symbol end actions. /// - [DataMember(Order = 8)] - public int SymbolEndActionsCount { get; set; } + public int SymbolEndActionsCount { get; set; } = 0; /// /// Count of registered syntax node actions. /// - [DataMember(Order = 9)] - public int SyntaxNodeActionsCount { get; set; } + public int SyntaxNodeActionsCount { get; set; } = 0; /// /// Count of registered code block start actions. /// - [DataMember(Order = 10)] - public int CodeBlockStartActionsCount { get; set; } + public int CodeBlockStartActionsCount { get; set; } = 0; /// /// Count of registered code block end actions. /// - [DataMember(Order = 11)] - public int CodeBlockEndActionsCount { get; set; } + public int CodeBlockEndActionsCount { get; set; } = 0; /// /// Count of registered code block actions. /// - [DataMember(Order = 12)] - public int CodeBlockActionsCount { get; set; } + public int CodeBlockActionsCount { get; set; } = 0; /// /// Count of registered operation actions. /// - [DataMember(Order = 13)] - public int OperationActionsCount { get; set; } + public int OperationActionsCount { get; set; } = 0; /// /// Count of registered operation block start actions. /// - [DataMember(Order = 14)] - public int OperationBlockStartActionsCount { get; set; } + public int OperationBlockStartActionsCount { get; set; } = 0; /// /// Count of registered operation block end actions. /// - [DataMember(Order = 15)] - public int OperationBlockEndActionsCount { get; set; } + public int OperationBlockEndActionsCount { get; set; } = 0; /// /// Count of registered operation block actions. /// - [DataMember(Order = 16)] - public int OperationBlockActionsCount { get; set; } + public int OperationBlockActionsCount { get; set; } = 0; /// /// Count of registered suppression actions. /// This is the same as count of s as each suppressor /// has a single suppression action, i.e. . /// - [DataMember(Order = 17)] - public int SuppressionActionsCount { get; set; } + public int SuppressionActionsCount { get; set; } = 0; /// /// 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 6da2b595ecbb4..cff2b5041ce61 100644 --- a/src/Compilers/Core/Portable/Text/TextChange.cs +++ b/src/Compilers/Core/Portable/Text/TextChange.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -16,19 +15,16 @@ 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 f76f2e587b9c2..fed431a15dad0 100644 --- a/src/Compilers/Core/Portable/Text/TextSpan.cs +++ b/src/Compilers/Core/Portable/Text/TextSpan.cs @@ -5,7 +5,6 @@ #nullable enable using System; -using System.Runtime.Serialization; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text @@ -14,7 +13,6 @@ 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 { /// @@ -40,7 +38,6 @@ public TextSpan(int start, int length) /// /// Start point of the span. /// - [DataMember(Order = 0)] public int Start { get; } /// @@ -51,7 +48,6 @@ public TextSpan(int start, int length) /// /// Length of the span. /// - [DataMember(Order = 1)] public int Length { get; } /// diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingNuGetTests.cs index fe8be5b6336f7..3f18c3565f2b2 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); 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(new ValueTask>(ImmutableArray.Empty)); + .Returns(Task.FromResult>(new List())); packageServiceMock.Setup(s => s.FindPackagesWithTypeAsync(NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); @@ -276,18 +276,17 @@ await TestInRegularAndScriptAsync( installerServiceMock.Verify(); } - private static ValueTask> CreateSearchResult( + private static Task> CreateSearchResult( string packageName, string typeName, ImmutableArray containingNamespaceNames) { return CreateSearchResult(new PackageWithTypeResult( - packageName: packageName, rank: 0, typeName: typeName, - version: null, containingNamespaceNames: containingNamespaceNames)); + packageName: packageName, typeName: typeName, version: null, + rank: 0, containingNamespaceNames: containingNamespaceNames)); } - private static ValueTask> CreateSearchResult(params PackageWithTypeResult[] results) - => new(ImmutableArray.Create(results)); + private static Task> CreateSearchResult(params PackageWithTypeResult[] results) + => Task.FromResult>(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/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs index d3ac21dece7cb..0ccbc0881c0aa 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 ValueTask OnReferenceFoundAsync(Document document, TextSpan span) + public async Task 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 ValueTask OnStartedAsync() => default; - public ValueTask OnCompletedAsync() => default; - public ValueTask OnFindInDocumentStartedAsync(Document document) => default; - public ValueTask OnFindInDocumentCompletedAsync(Document document) => default; + public Task OnStartedAsync() => Task.CompletedTask; + public Task OnCompletedAsync() => Task.CompletedTask; + public Task OnFindInDocumentStartedAsync(Document document) => Task.CompletedTask; + public Task OnFindInDocumentCompletedAsync(Document document) => Task.CompletedTask; // 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 ValueTask GetDefinitionItemAsync(ISymbol definition) + private async Task GetDefinitionItemAsync(ISymbol definition) { var cancellationToken = _context.CancellationToken; using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) @@ -112,13 +112,13 @@ private async ValueTask GetDefinitionItemAsync(ISymbol definitio } } - public async ValueTask OnDefinitionFoundAsync(ISymbol definition) + public async Task OnDefinitionFoundAsync(ISymbol definition) { var definitionItem = await GetDefinitionItemAsync(definition).ConfigureAwait(false); await _context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false); } - public async ValueTask OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location) + public async Task 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_FindImplementations.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs index 92042144e18a4..cbe6ed362d654 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs +++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindImplementations.cs @@ -51,11 +51,15 @@ 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.TryInvokeAsync( + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteFindUsagesService.FindImplementationsAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindImplementationsAsync(solutionInfo, symbolAndProjectId, cancellationToken), + new object[] + { + SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken), + }, serverCallback, cancellationToken).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService_FindReferences.cs index 8b84ca2550f64..8aca444539046 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 = FindSymbols.FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol); + var options = 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,11 +138,16 @@ 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.TryInvokeAsync( + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteFindUsagesService.FindReferencesAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindReferencesAsync(solutionInfo, symbolAndProjectId, options, cancellationToken), + new object[] + { + SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken), + SerializableFindReferencesSearchOptions.Dehydrate(options), + }, serverCallback, cancellationToken).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs b/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs index 1133af77c5313..183d84c17d696 100644 --- a/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs +++ b/src/EditorFeatures/Core/FindUsages/FindUsagesContext.cs @@ -15,7 +15,7 @@ internal abstract class FindUsagesContext : IFindUsagesContext public IStreamingProgressTracker ProgressTracker { get; } protected FindUsagesContext() - => this.ProgressTracker = new StreamingProgressTracker(this.ReportProgressAsync); + => this.ProgressTracker = new StreamingProgressTracker((current, max) => this.ReportProgressAsync(current, max).AsTask()); public virtual ValueTask ReportMessageAsync(string message) => default; diff --git a/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs new file mode 100644 index 0000000000000..3fbc05fd74459 --- /dev/null +++ b/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs @@ -0,0 +1,190 @@ +// 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).AsTask(); + + [Obsolete] + public Task ReportProgressAsync(int current, int maximum) + => _context.ReportProgressAsync(current, maximum).AsTask(); + + public Task SetSearchTitleAsync(string title) + => _context.SetSearchTitleAsync(title).AsTask(); + + public Task OnDefinitionFoundAsync(SerializableDefinitionItem definition) + { + var id = definition.Id; + var rehydrated = definition.Rehydrate(_solution); + + lock (_idToDefinition) + { + _idToDefinition.Add(id, rehydrated); + } + + return _context.OnDefinitionFoundAsync(rehydrated).AsTask(); + } + + public Task OnReferenceFoundAsync(SerializableSourceReferenceItem reference) + => _context.OnReferenceFoundAsync(reference.Rehydrate(_solution, GetDefinition(reference.DefinitionId))).AsTask(); + + 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/SymbolSearch/SymbolSearchUpdateEngine.Update.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs index e7795035e3e58..97cc1a7fb9219 100644 --- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs +++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs @@ -13,9 +13,11 @@ 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 @@ -54,18 +56,19 @@ internal partial class SymbolSearchUpdateEngine private readonly IDatabaseFactoryService _databaseFactoryService; private readonly Func _reportAndSwallowException; - private ValueTask LogInfoAsync(string text, CancellationToken cancellationToken) - => _logService.LogInfoAsync(text, cancellationToken); + private Task LogInfoAsync(string text) => _logService.LogInfoAsync(text); - private ValueTask LogExceptionAsync(Exception e, string text, CancellationToken cancellationToken) - => _logService.LogExceptionAsync(e.ToString(), 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); /// /// 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. /// - public ValueTask UpdateContinuouslyAsync(string source, string localSettingsDirectory, CancellationToken cancellationToken) + internal Task 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. @@ -75,7 +78,7 @@ public ValueTask UpdateContinuouslyAsync(string source, string localSettingsDire if (ourSentinel != currentSentinel) { // We already have an update loop for this source. Nothing for us to do. - return default; + return Task.CompletedTask; } // We were the first ones to try to update this source. Spawn off a task to do @@ -101,7 +104,7 @@ public Updater(SymbolSearchUpdateEngine service, string source, string localSett /// /// Internal for testing purposes. /// - internal async ValueTask UpdateInBackgroundAsync(CancellationToken cancellationToken) + internal async Task UpdateInBackgroundAsync(CancellationToken cancellationToken) { // We only support this single source currently. if (_source != NugetOrgSource) @@ -112,17 +115,17 @@ internal async ValueTask UpdateInBackgroundAsync(CancellationToken cancellationT // Keep on looping until we're told to shut down. while (!cancellationToken.IsCancellationRequested) { - await _service.LogInfoAsync("Starting update", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Starting update").ConfigureAwait(false); try { var delayUntilNextUpdate = await UpdateDatabaseInBackgroundWorkerAsync(cancellationToken).ConfigureAwait(false); - await _service.LogInfoAsync($"Waiting {delayUntilNextUpdate} until next update", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Waiting {delayUntilNextUpdate} until next update").ConfigureAwait(false); await Task.Delay(delayUntilNextUpdate, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { - await _service.LogInfoAsync("Update canceled. Ending update loop", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Update canceled. Ending update loop").ConfigureAwait(false); return; } } @@ -181,12 +184,12 @@ private async Task UpdateDatabaseInBackgroundWorkerAsync(CancellationT if (_service._ioService.Exists(databaseFileInfo)) { - await _service.LogInfoAsync("Local database file exists. Patching local database", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Local database file exists. Patching local database").ConfigureAwait(false); return await PatchLocalDatabaseAsync(databaseFileInfo, cancellationToken).ConfigureAwait(false); } else { - await _service.LogInfoAsync("Local database file does not exist. Downloading full database", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Local database file does not exist. Downloading full database").ConfigureAwait(false); return await DownloadFullDatabaseAsync(databaseFileInfo, cancellationToken).ConfigureAwait(false); } } @@ -204,23 +207,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}", cancellationToken).ConfigureAwait(false); + await _service.LogExceptionAsync(e, $"Error occurred updating. Retrying update in {delay}").ConfigureAwait(false); return delay; } } private async Task CleanCacheDirectoryAsync(CancellationToken cancellationToken) { - await _service.LogInfoAsync("Cleaning cache directory", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Cleaning cache directory").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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Creating cache directory").ConfigureAwait(false); // (intentionally not wrapped in IOUtilities. If this throws we want to restart). _service._ioService.Create(_cacheDirectoryInfo); - await _service.LogInfoAsync("Cache directory created", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Cache directory created").ConfigureAwait(false); } cancellationToken.ThrowIfCancellationRequested(); @@ -236,22 +239,22 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo { var serverPath = Invariant($"Elfie_V{AddReferenceDatabaseTextFileFormatVersion}/Latest.xml"); - await _service.LogInfoAsync($"Downloading and processing full database: {serverPath}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Downloading and processing full database: {serverPath}").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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Downloading and processing full database completed").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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Processing full database element").ConfigureAwait(false); // Convert the database contents in the XML to a byte[]. - var (succeeded, contentBytes) = await TryParseDatabaseElementAsync(element, cancellationToken).ConfigureAwait(false); + var (succeeded, contentBytes) = await TryParseDatabaseElementAsync(element).ConfigureAwait(false); if (!succeeded) { @@ -261,7 +264,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}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Unable to parse full database element. Update again in {failureDelay}").ConfigureAwait(false); return (succeeded: false, failureDelay); } @@ -271,7 +274,7 @@ private async Task DownloadFullDatabaseAsync(FileInfo databaseFileInfo // searching. try { - await CreateAndSetInMemoryDatabaseAsync(bytes, cancellationToken).ConfigureAwait(false); + await CreateAndSetInMemoryDatabaseAsync(bytes).ConfigureAwait(false); } catch (Exception e) when (_service._reportAndSwallowException(e)) { @@ -280,7 +283,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}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Unable to create database from full database element. Update again in {failureDelay}").ConfigureAwait(false); return (succeeded: false, failureDelay); } @@ -290,13 +293,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}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Processing full database element completed. Update again in {delay}").ConfigureAwait(false); return (succeeded: true, delay); } private async Task WriteDatabaseFileAsync(FileInfo databaseFileInfo, byte[] bytes, CancellationToken cancellationToken) { - await _service.LogInfoAsync("Writing database file", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Writing database file").ConfigureAwait(false); await RepeatIOAsync( async () => @@ -304,7 +307,7 @@ await RepeatIOAsync( var guidString = Guid.NewGuid().ToString(); var tempFilePath = Path.Combine(_cacheDirectoryInfo.FullName, guidString + ".tmp"); - await _service.LogInfoAsync($"Temp file path: {tempFilePath}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Temp file path: {tempFilePath}").ConfigureAwait(false); try { @@ -313,25 +316,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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Writing temp file").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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Writing temp file completed").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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Replacing database file").ConfigureAwait(false); _service._ioService.Replace(tempFilePath, databaseFileInfo.FullName, destinationBackupFileName: null, ignoreMetadataErrors: true); - await _service.LogInfoAsync("Replace database file completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Replace database file completed").ConfigureAwait(false); } else { - await _service.LogInfoAsync("Moving database file", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Moving database file").ConfigureAwait(false); _service._ioService.Move(tempFilePath, databaseFileInfo.FullName); - await _service.LogInfoAsync("Moving database file completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Moving database file completed").ConfigureAwait(false); } } finally @@ -342,17 +345,17 @@ await RepeatIOAsync( } }, cancellationToken).ConfigureAwait(false); - await _service.LogInfoAsync("Writing database file completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Writing database file completed").ConfigureAwait(false); } private async Task PatchLocalDatabaseAsync(FileInfo databaseFileInfo, CancellationToken cancellationToken) { - await _service.LogInfoAsync("Patching local database", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Patching local database").ConfigureAwait(false); - await _service.LogInfoAsync("Reading in local database", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Reading in local database").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}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Reading in local database completed. databaseBytes.Length={databaseBytes.Length}").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 @@ -361,24 +364,24 @@ private async Task PatchLocalDatabaseAsync(FileInfo databaseFileInfo, AddReferenceDatabase database; try { - database = await CreateAndSetInMemoryDatabaseAsync(databaseBytes, cancellationToken).ConfigureAwait(false); + database = await CreateAndSetInMemoryDatabaseAsync(databaseBytes).ConfigureAwait(false); } catch (Exception e) when (_service._reportAndSwallowException(e)) { - await _service.LogExceptionAsync(e, "Error creating database from local copy. Downloading full database", cancellationToken).ConfigureAwait(false); + await _service.LogExceptionAsync(e, "Error creating database from local copy. Downloading full database").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, cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Downloading and processing patch file: " + serverPath).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", cancellationToken).ConfigureAwait(false); - await _service.LogInfoAsync("Patching local database completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Downloading and processing patch file completed").ConfigureAwait(false); + await _service.LogInfoAsync("Patching local database completed").ConfigureAwait(false); return delayUntilUpdate; } @@ -389,9 +392,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, CancellationToken cancellationToken) + private async Task CreateAndSetInMemoryDatabaseAsync(byte[] bytes) { - var database = await CreateDatabaseFromBytesAsync(bytes, cancellationToken).ConfigureAwait(false); + var database = await CreateDatabaseFromBytesAsync(bytes).ConfigureAwait(false); _service._sourceToDatabase[_source] = new AddReferenceDatabaseWrapper(database); return database; } @@ -401,11 +404,11 @@ private async Task ProcessPatchXElementAsync( { try { - await _service.LogInfoAsync("Processing patch element", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Processing patch element").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}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Processing patch element completed. Update again in {delayUntilUpdate.Value}").ConfigureAwait(false); return delayUntilUpdate.Value; } @@ -413,7 +416,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", cancellationToken).ConfigureAwait(false); + await _service.LogExceptionAsync(e, "Error occurred while processing patch element. Downloading full database").ConfigureAwait(false); // Fall through and download full database. } @@ -427,25 +430,25 @@ private async Task ProcessPatchXElementAsync( if (upToDate) { - await _service.LogInfoAsync("Local version is up to date", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Local version is up to date").ConfigureAwait(false); return _service._delayService.UpdateSucceededDelay; } if (tooOld) { - await _service.LogInfoAsync("Local version too old", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Local version too old").ConfigureAwait(false); return null; } - await _service.LogInfoAsync($"Got patch. databaseBytes.Length={databaseBytes.Length} patchBytes.Length={patchBytes.Length}.", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Got patch. databaseBytes.Length={databaseBytes.Length} patchBytes.Length={patchBytes.Length}.").ConfigureAwait(false); // We have patch data. Apply it to our current database bytes to produce the new // database. - await _service.LogInfoAsync("Applying patch", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Applying patch").ConfigureAwait(false); var finalBytes = _service._patchService.ApplyPatch(databaseBytes, patchBytes); - await _service.LogInfoAsync($"Applying patch completed. finalBytes.Length={finalBytes.Length}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Applying patch completed. finalBytes.Length={finalBytes.Length}").ConfigureAwait(false); - await CreateAndSetInMemoryDatabaseAsync(finalBytes, cancellationToken).ConfigureAwait(false); + await CreateAndSetInMemoryDatabaseAsync(finalBytes).ConfigureAwait(false); await WriteDatabaseFileAsync(databaseFileInfo, finalBytes, cancellationToken).ConfigureAwait(false); @@ -480,17 +483,17 @@ private static void ParsePatchElement(XElement patchElement, out bool upToDate, } } - private async Task CreateDatabaseFromBytesAsync(byte[] bytes, CancellationToken cancellationToken) + private async Task CreateDatabaseFromBytesAsync(byte[] bytes) { - await _service.LogInfoAsync("Creating database from bytes", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Creating database from bytes").ConfigureAwait(false); var result = _service._databaseFactoryService.CreateDatabaseFromBytes(bytes); - await _service.LogInfoAsync("Creating database from bytes completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Creating database from bytes completed").ConfigureAwait(false); return result; } private async Task DownloadFileAsync(string serverPath, CancellationToken cancellationToken) { - await _service.LogInfoAsync("Creating download client: " + serverPath, cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Creating download client: " + serverPath).ConfigureAwait(false); // Create a client that will attempt to download the specified file. The client works // in the following manner: @@ -506,18 +509,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", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Creating download client completed").ConfigureAwait(false); // Poll the client every minute until we get the file. while (true) { cancellationToken.ThrowIfCancellationRequested(); - var resultOpt = await TryDownloadFileAsync(client, cancellationToken).ConfigureAwait(false); + var resultOpt = await TryDownloadFileAsync(client).ConfigureAwait(false); if (resultOpt == null) { var delay = _service._delayService.CachePollDelay; - await _service.LogInfoAsync($"File not downloaded. Trying again in {delay}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"File not downloaded. Trying again in {delay}").ConfigureAwait(false); await Task.Delay(delay, cancellationToken).ConfigureAwait(false); } else @@ -529,9 +532,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, CancellationToken cancellationToken) + private async Task TryDownloadFileAsync(IRemoteControlClient client) { - await _service.LogInfoAsync("Read file from client", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Read file from client").ConfigureAwait(false); // "ReturnsNull": Only return a file if we have it locally *and* it's not older than our polling time (1 day). @@ -539,12 +542,12 @@ private async Task TryDownloadFileAsync(IRemoteControlClient client, C if (stream == null) { - await _service.LogInfoAsync("Read file completed. Client returned no data", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Read file completed. Client returned no data").ConfigureAwait(false); return null; } - await _service.LogInfoAsync("Read file completed. Client returned data", cancellationToken).ConfigureAwait(false); - await _service.LogInfoAsync("Converting data to XElement", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Read file completed. Client returned data").ConfigureAwait(false); + await _service.LogInfoAsync("Converting data to XElement").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 @@ -559,7 +562,7 @@ private async Task TryDownloadFileAsync(IRemoteControlClient client, C using var reader = XmlReader.Create(stream, settings); var result = XElement.Load(reader); - await _service.LogInfoAsync("Converting data to XElement completed", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Converting data to XElement completed").ConfigureAwait(false); return result; } @@ -585,15 +588,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}", cancellationToken).ConfigureAwait(false); + await _service.LogExceptionAsync(e, $"Operation failed. Trying again after {delay}").ConfigureAwait(false); await Task.Delay(delay, cancellationToken).ConfigureAwait(false); } } } - private async Task<(bool succeeded, byte[] contentBytes)> TryParseDatabaseElementAsync(XElement element, CancellationToken cancellationToken) + private async Task<(bool succeeded, byte[] contentBytes)> TryParseDatabaseElementAsync(XElement element) { - await _service.LogInfoAsync("Parsing database element", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync("Parsing database element").ConfigureAwait(false); var contentsAttribute = element.Attribute(ContentAttributeName); if (contentsAttribute == null) { @@ -602,7 +605,7 @@ private async Task RepeatIOAsync(Func action, CancellationToken cancellati return (succeeded: false, (byte[])null); } - var contentBytes = await ConvertContentAttributeAsync(contentsAttribute, cancellationToken).ConfigureAwait(false); + var contentBytes = await ConvertContentAttributeAsync(contentsAttribute).ConfigureAwait(false); var checksumAttribute = element.Attribute(ChecksumAttributeName); if (checksumAttribute != null) @@ -625,7 +628,7 @@ private async Task RepeatIOAsync(Func action, CancellationToken cancellati return (succeeded: true, contentBytes); } - private async Task ConvertContentAttributeAsync(XAttribute contentsAttribute, CancellationToken cancellationToken) + private async Task ConvertContentAttributeAsync(XAttribute contentsAttribute) { var text = contentsAttribute.Value; var compressedBytes = Convert.FromBase64String(text); @@ -640,7 +643,7 @@ private async Task ConvertContentAttributeAsync(XAttribute contentsAttri var bytes = outStream.ToArray(); - await _service.LogInfoAsync($"Parsing complete. bytes.length={bytes.Length}", cancellationToken).ConfigureAwait(false); + await _service.LogInfoAsync($"Parsing complete. bytes.length={bytes.Length}").ConfigureAwait(false); return bytes; } } diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs index 077bf39342f07..1cb312506eacd 100644 --- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs +++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.cs @@ -66,20 +66,20 @@ internal SymbolSearchUpdateEngine( _reportAndSwallowException = reportAndSwallowException; } - public ValueTask> FindPackagesWithTypeAsync( + public Task> FindPackagesWithTypeAsync( string source, string name, int arity, CancellationToken cancellationToken) { if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper)) { // Don't have a database to search. - return new(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } var database = databaseWrapper.Database; if (name == "var") { // never find anything named 'var'. - return new(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } var query = new MemberQuery(name, isFullSuffix: true, isFullNamespace: false); @@ -102,16 +102,16 @@ public ValueTask> FindPackagesWithTypeAsyn } } - return new(result.ToImmutableAndFree()); + return Task.FromResult(result.ToImmutableAndFree()); } - public ValueTask> FindPackagesWithAssemblyAsync( + public Task> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken) { if (!_sourceToDatabase.TryGetValue(source, out var databaseWrapper)) { // Don't have a database to search. - return new(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } var result = ArrayBuilder.GetInstance(); @@ -132,35 +132,33 @@ public ValueTask> FindPackagesWithAsse // Ignore any reference assembly results. if (symbol.PackageName.ToString() != MicrosoftAssemblyReferencesName) { - var version = database.GetPackageVersion(symbol.Index).ToString(); - result.Add(new PackageWithAssemblyResult( symbol.PackageName.ToString(), - GetRank(symbol), - string.IsNullOrWhiteSpace(version) ? null : version)); + database.GetPackageVersion(symbol.Index).ToString(), + GetRank(symbol))); } } } } - return new(result.ToImmutableAndFree()); + return Task.FromResult(result.ToImmutableAndFree()); } - public ValueTask> FindReferenceAssembliesWithTypeAsync( + public Task> 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 new(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } var database = databaseWrapper.Database; if (name == "var") { // never find anything named 'var'. - return new(ImmutableArray.Empty); + return SpecializedTasks.EmptyImmutableArray(); } var query = new MemberQuery(name, isFullSuffix: true, isFullNamespace: false); @@ -188,7 +186,7 @@ public ValueTask> FindReferenceA } } - return new(results.ToImmutableAndFree()); + return Task.FromResult(results.ToImmutableAndFree()); } private static List FilterToViableTypes(PartialArray symbols) @@ -213,9 +211,9 @@ private PackageWithTypeResult CreateResult(AddReferenceDatabase database, Symbol return new PackageWithTypeResult( packageName: packageName, - rank: GetRank(type), typeName: type.Name.ToString(), - version: string.IsNullOrWhiteSpace(version) ? null : version, + version: version, + rank: GetRank(type), containingNamespaceNames: nameParts.ToImmutableAndFree()); } diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs index dbf4d896394ec..1224ad7545023 100644 --- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs +++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngineFactory.cs @@ -4,11 +4,13 @@ #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 { @@ -30,8 +32,9 @@ public static async Task CreateEngineAsync( var client = await RemoteHostClient.TryGetClientAsync(workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var connection = await client.CreateConnectionAsync(logService, cancellationToken).ConfigureAwait(false); - return new RemoteUpdateEngine(connection); + var callbackObject = new CallbackObject(logService); + var session = await client.CreateConnectionAsync(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, callbackObject, cancellationToken).ConfigureAwait(false); + return new RemoteUpdateEngine(workspace, session); } // Couldn't go out of proc. Just do everything inside the current process. @@ -50,64 +53,97 @@ public static ISymbolSearchUpdateEngine CreateEngineInProcess(ISymbolSearchLogSe private sealed class NoOpUpdateEngine : ISymbolSearchUpdateEngine { - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) + => SpecializedTasks.EmptyImmutableArray(); - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + => SpecializedTasks.EmptyImmutableArray(); - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) + => SpecializedTasks.EmptyImmutableArray(); - public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) - => default; + public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory) + => Task.CompletedTask; } private sealed class RemoteUpdateEngine : ISymbolSearchUpdateEngine { - private readonly RemoteServiceConnection _connection; + private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); - public RemoteUpdateEngine(RemoteServiceConnection connection) - => _connection = connection; + private readonly Workspace _workspace; + private readonly RemoteServiceConnection _session; + + public RemoteUpdateEngine( + Workspace workspace, + RemoteServiceConnection session) + { + _workspace = workspace; + _session = session; + } public void Dispose() - => _connection.Dispose(); + { + _session.Dispose(); + } - public async ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + public async Task> FindPackagesWithTypeAsync( + string source, string name, int arity, CancellationToken cancellationToken) { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), + var results = await _session.RunRemoteAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithTypeAsync), + solution: null, + new object[] { source, name, arity }, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value : ImmutableArray.Empty; + return results.ToImmutableArray(); } - public async ValueTask> FindPackagesWithAssemblyAsync( + public async Task> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken) { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), + var results = await _session.RunRemoteAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithAssemblyAsync), + solution: null, + new object[] { source, assemblyName }, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value : ImmutableArray.Empty; + return results.ToImmutableArray(); } - public async ValueTask> FindReferenceAssembliesWithTypeAsync( + public async Task> FindReferenceAssembliesWithTypeAsync( string name, int arity, CancellationToken cancellationToken) { - var result = await _connection.TryInvokeAsync>( - (service, cancellationToken) => service.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), + var results = await _session.RunRemoteAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindReferenceAssembliesWithTypeAsync), + solution: null, + new object[] { name, arity }, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value : ImmutableArray.Empty; + return results.ToImmutableArray(); } - public async ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) + 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) { - _ = await _connection.TryInvokeAsync( - (service, cancellationToken) => service.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken), - cancellationToken).ConfigureAwait(false); + _logService = logService; } + + 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/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index b8d11886594af..06e6fcc240250 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.Diagnostics.Single().diagnosticMap; - var diagnostic = kind == AnalysisKind.Syntax ? builder.Syntax.Single().Item2.Single() : builder.Semantic.Single().Item2.Single(); + var builder = diagnosticsMap.AnalysisResult.Values.Single(); + var diagnostic = kind == AnalysisKind.Syntax ? builder.SyntaxLocals.Values.Single().Single() : builder.SemanticLocals.Values.Single().Single(); Assert.Equal(CancellationTestAnalyzer.NonCanceledDiagnosticId, diagnostic.Id); } diff --git a/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj b/src/EditorFeatures/Test/Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj index ca47481e9b233..8298048cd39a5 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/TestUtilities/CodeLens/AbstractCodeLensTest.cs b/src/EditorFeatures/TestUtilities/CodeLens/AbstractCodeLensTest.cs index ee3f833955d8e..6109f4dd130ba 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.Value.Count); - Assert.Equal(isCapped, result.Value.IsCapped); + Assert.Equal(expected, result.Count); + Assert.Equal(isCapped, result.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); - Assert.True(result.HasValue); - Assert.Equal(expected, result.Value.Length); + var count = result.Count(); + Assert.Equal(expected, count); } } } @@ -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); - Assert.True(result.HasValue); - Assert.Equal(expected, result.Value.Length); + var count = result.Count(); + Assert.Equal(expected, count); } } } diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb index 6adcea71f3438..348e34cb163f5 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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(New ValueTask(Of ImmutableArray(Of ReferenceAssemblyWithTypeResult))(ImmutableArray(Of ReferenceAssemblyWithTypeResult).Empty)) + Returns(Task.FromResult(Of IList(Of ReferenceAssemblyWithTypeResult))(New List(Of ReferenceAssemblyWithTypeResult))) 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 ValueTask(Of ImmutableArray(Of PackageWithTypeResult)) + Private Shared Function CreateSearchResult(packageName As String, typeName As String, nameParts As ImmutableArray(Of String)) As Task(Of IList(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 ValueTask(Of ImmutableArray(Of PackageWithTypeResult)) - Return New ValueTask(Of ImmutableArray(Of PackageWithTypeResult))(ImmutableArray.Create(results)) + Private Shared Function CreateSearchResult(ParamArray results As PackageWithTypeResult()) As Task(Of IList(Of PackageWithTypeResult)) + Return Task.FromResult(Of IList(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 850960da63803..1dd0a88aa85c3 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs @@ -59,15 +59,26 @@ public async Task> GetFixesAsync( var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); if (client != null) { - var callbackTarget = new RemoteAddImportServiceCallback(symbolSearchService); + var callbackTarget = new RemoteSymbolSearchService(symbolSearchService); - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteAddImportFeatureService.GetFixesAsync), document.Project.Solution, - (service, solutionInfo, cancellationToken) => service.GetFixesAsync(solutionInfo, document.Id, span, diagnosticId, maxResults, placeSystemNamespaceFirst, searchReferenceAssemblies, packageSources, cancellationToken), + new object[] + { + document.Id, + span, + diagnosticId, + maxResults, + placeSystemNamespaceFirst, + searchReferenceAssemblies, + packageSources + }, callbackTarget, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value : ImmutableArray.Empty; + return result.ToImmutableArray(); } return await GetFixesInCurrentProcessAsync( diff --git a/src/Features/Core/Portable/AddImport/AddImportFixData.cs b/src/Features/Core/Portable/AddImport/AddImportFixData.cs index bf74a8c8dfa2a..7d7ce3086fcfb 100644 --- a/src/Features/Core/Portable/AddImport/AddImportFixData.cs +++ b/src/Features/Core/Portable/AddImport/AddImportFixData.cs @@ -4,17 +4,14 @@ 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 { - [DataContract] - internal sealed class AddImportFixData + internal class AddImportFixData { - [DataMember(Order = 0)] public AddImportFixKind Kind { get; } /// @@ -23,34 +20,29 @@ internal sealed 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. /// - [DataMember(Order = 1)] - public readonly ImmutableArray TextChanges; + public IList TextChanges { get; } /// /// String to display in the lightbulb menu. /// - [DataMember(Order = 2)] - public readonly string Title; + public string Title { get; private set; } /// /// Tags that control what glyph is displayed in the lightbulb menu. /// - [DataMember(Order = 3)] - public readonly ImmutableArray Tags; + public IList Tags { get; private set; } /// /// The priority this item should have in the lightbulb list. /// - [DataMember(Order = 4)] - public readonly CodeActionPriority Priority; + public CodeActionPriority Priority { get; private set; } #region When adding P2P references. /// /// The optional id for a we'd like to add a reference to. /// - [DataMember(Order = 5)] - public readonly ProjectId ProjectReferenceToAdd; + public ProjectId ProjectReferenceToAdd { get; private set; } #endregion @@ -61,104 +53,84 @@ internal sealed class AddImportFixData /// is the id for the we can find that /// referenced from. /// - [DataMember(Order = 6)] - public readonly ProjectId PortableExecutableReferenceProjectId; + public ProjectId PortableExecutableReferenceProjectId { get; private set; } /// /// If we want to add a metadata reference, this /// is the for it. /// - [DataMember(Order = 7)] - public readonly string PortableExecutableReferenceFilePathToAdd; + public string PortableExecutableReferenceFilePathToAdd { get; private set; } #endregion #region When adding an assembly reference - [DataMember(Order = 8)] - public readonly string AssemblyReferenceAssemblyName; - - [DataMember(Order = 9)] - public readonly string AssemblyReferenceFullyQualifiedTypeName; + public string AssemblyReferenceAssemblyName { get; private set; } + public string AssemblyReferenceFullyQualifiedTypeName { get; private set; } #endregion #region When adding a package reference - [DataMember(Order = 10)] - public readonly string PackageSource; - - [DataMember(Order = 11)] - public readonly string PackageName; - - [DataMember(Order = 12)] - public readonly string PackageVersionOpt; + public string PackageSource { get; private set; } + public string PackageName { get; private set; } + public string PackageVersionOpt { get; private set; } #endregion - // Must be public since it's used for deserialization. - public AddImportFixData( + private AddImportFixData( AddImportFixKind kind, - 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) + ImmutableArray textChanges) { Kind = kind; TextChanges = textChanges; - Title = title; - Tags = tags; - Priority = priority; - ProjectReferenceToAdd = projectReferenceToAdd; - PortableExecutableReferenceProjectId = portableExecutableReferenceProjectId; - PortableExecutableReferenceFilePathToAdd = portableExecutableReferenceFilePathToAdd; - AssemblyReferenceAssemblyName = assemblyReferenceAssemblyName; - AssemblyReferenceFullyQualifiedTypeName = assemblyReferenceFullyQualifiedTypeName; - PackageSource = packageSource; - PackageName = packageName; - PackageVersionOpt = packageVersionOpt; + Tags = ImmutableArray.Empty; } public static AddImportFixData CreateForProjectSymbol(ImmutableArray textChanges, string title, ImmutableArray tags, CodeActionPriority priority, ProjectId projectReferenceToAdd) - => new(AddImportFixKind.ProjectSymbol, - textChanges, - title: title, - tags: tags, - priority: priority, - projectReferenceToAdd: projectReferenceToAdd); + { + return new AddImportFixData(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) - => new(AddImportFixKind.MetadataSymbol, - textChanges, - title: title, - tags: tags, - priority: priority, - portableExecutableReferenceProjectId: portableExecutableReferenceProjectId, - portableExecutableReferenceFilePathToAdd: portableExecutableReferenceFilePathToAdd); + { + return new AddImportFixData(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) - => new(AddImportFixKind.ReferenceAssemblySymbol, - textChanges, - title: title, - tags: WellKnownTagArrays.AddReference, - priority: CodeActionPriority.Low, - assemblyReferenceAssemblyName: assemblyReferenceAssemblyName, - assemblyReferenceFullyQualifiedTypeName: assemblyReferenceFullyQualifiedTypeName); + { + return new AddImportFixData(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) - => new(AddImportFixKind.PackageSymbol, - textChanges, - packageSource: packageSource, - priority: CodeActionPriority.Low, - packageName: packageName, - packageVersionOpt: packageVersionOpt); + { + return new AddImportFixData(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 26cc554d43b2d..ce7827e4e1849 100644 --- a/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs +++ b/src/Features/Core/Portable/AddImport/Remote/AbstractAddImportFeatureService_Remote.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.SymbolSearch; @@ -25,21 +24,39 @@ internal abstract partial class AbstractAddImportFeatureService - private sealed class RemoteAddImportServiceCallback : IRemoteMissingImportDiscoveryService.ICallback + private sealed class RemoteSymbolSearchService : IRemoteSymbolSearchUpdateEngine { private readonly ISymbolSearchService _symbolSearchService; - public RemoteAddImportServiceCallback(ISymbolSearchService symbolSearchService) + public RemoteSymbolSearchService(ISymbolSearchService symbolSearchService) => _symbolSearchService = symbolSearchService; - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => _symbolSearchService.FindPackagesWithTypeAsync(source, name, arity, cancellationToken); + public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory) + { + // Remote side should never call this. + throw new NotImplementedException(); + } - public ValueTask> FindPackagesWithAssemblyAsync(string source, string name, CancellationToken cancellationToken) - => _symbolSearchService.FindPackagesWithAssemblyAsync(source, name, cancellationToken); + public Task> FindPackagesWithTypeAsync( + string source, string name, int arity, CancellationToken cancellationToken) + { + return _symbolSearchService.FindPackagesWithTypeAsync( + source, name, arity, cancellationToken); + } - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => _symbolSearchService.FindReferenceAssembliesWithTypeAsync(name, arity, 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); + } } } } diff --git a/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs new file mode 100644 index 0000000000000..acdcf598092d3 --- /dev/null +++ b/src/Features/Core/Portable/AddImport/Remote/IRemoteAddImportFeatureService.cs @@ -0,0 +1,20 @@ +// 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 deleted file mode 100644 index d9b57e4966f20..0000000000000 --- a/src/Features/Core/Portable/AddImport/Remote/IRemoteMissingImportDiscoveryService.cs +++ /dev/null @@ -1,28 +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.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 fe28b0551299a..f0419302bfa0e 100644 --- a/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs +++ b/src/Features/Core/Portable/CodeLens/CodeLensReferencesService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Threading; @@ -24,9 +23,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 : struct + int searchCap, CancellationToken cancellationToken) where T : class { var document = solution.GetDocument(documentId); if (document == null) @@ -66,7 +65,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( @@ -181,7 +180,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 => @@ -192,7 +191,7 @@ private static SyntaxNode GetEnclosingCodeElementNode(Document document, SyntaxT var result = await Task.WhenAll(referenceTasks).ConfigureAwait(false); - return result.ToImmutableArray(); + return (IEnumerable)result; }, onCapped: null, searchCap: 0, cancellationToken: cancellationToken).ConfigureAwait(false); } @@ -239,7 +238,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 => @@ -251,7 +250,7 @@ private static async Task TryGetMethodDescriptorAsync var result = await Task.WhenAll(descriptorTasks).ConfigureAwait(false); - return result.OfType().ToImmutableArray(); + return result.OfType(); }, 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 d96dce7f3cefe..4fa7d213438e8 100644 --- a/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs +++ b/src/Features/Core/Portable/CodeLens/ICodeLensReferencesService.cs @@ -2,10 +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. -#nullable enable - using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -21,21 +18,23 @@ 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 f4d8259ef4e9c..2b4bce0def2a7 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.Immutable; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Remote; @@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.CodeLens { internal interface IRemoteCodeLensReferencesService { - 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); + 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); } } diff --git a/src/Features/Core/Portable/CodeLens/ReferenceCount.cs b/src/Features/Core/Portable/CodeLens/ReferenceCount.cs index d6f73c23cb68b..619acedfefc87 100644 --- a/src/Features/Core/Portable/CodeLens/ReferenceCount.cs +++ b/src/Features/Core/Portable/CodeLens/ReferenceCount.cs @@ -2,26 +2,21 @@ // 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. /// - [DataContract] - internal readonly struct ReferenceCount + internal class 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 2e3767f4277a3..bf11aaba08586 100644 --- a/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs +++ b/src/Features/Core/Portable/CodeLens/ReferenceLocationDescriptor.cs @@ -3,110 +3,91 @@ // 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 { - /// - /// Fully qualified name of the symbol containing the reference location - /// - [DataMember(Order = 0)] - public string LongDescription { get; } + public Guid ProjectGuid { get; } - /// - /// Language of the reference location - /// - [DataMember(Order = 1)] - public string Language { get; } + public Guid DocumentGuid { get; } /// - /// The kind of symbol containing the reference location (such as type, method, property, etc.) + /// Document's file path /// - [DataMember(Order = 2)] - public Glyph? Glyph { get; } + public string FilePath { 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; } - [DataMember(Order = 7)] - public Guid ProjectGuid { get; } + /// + /// Language of the reference location + /// + public string Language { get; } - [DataMember(Order = 8)] - public Guid DocumentGuid { get; } + /// + /// Fully qualified name of the symbol containing the reference location + /// + public string LongDescription { get; } /// - /// Document's file path + /// The kind of symbol containing the reference location (such as type, method, property, etc.) /// - [DataMember(Order = 9)] - public string FilePath { get; } + public Glyph? Glyph { 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 482056798494d..1d686c6a876dd 100644 --- a/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs +++ b/src/Features/Core/Portable/CodeLens/ReferenceMethodDescriptor.cs @@ -2,34 +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; - 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 /// @@ -45,5 +24,20 @@ 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 65405868ae02f..4ea3b8d125e7b 100644 --- a/src/Features/Core/Portable/Common/TaggedText.cs +++ b/src/Features/Core/Portable/Common/TaggedText.cs @@ -6,7 +6,6 @@ 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; @@ -17,39 +16,33 @@ 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 4368a910cce6d..1e920cb0e1b34 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.cs @@ -7,6 +7,7 @@ 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; @@ -34,52 +35,39 @@ public static async Task> GetUn bool forceIndexCreation, CancellationToken cancellationToken) { - SerializableUnimportedExtensionMethods items; - - var ticks = Environment.TickCount; - - var project = document.Project; - var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); - if (client != null) + async Task<(ImmutableArray, StatisticCounter)> GetItemsAsync() { - var receiverTypeSymbolKeyData = SymbolKey.CreateString(receiverTypeSymbol, cancellationToken); + var project = document.Project; - 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 client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + if (client != null) { - return ImmutableArray.Empty; + 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); } - items = result.Value; - } - else - { - items = await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false); + return await GetUnimportedExtensionMethodsInCurrentProcessAsync(document, position, receiverTypeSymbol, namespaceInScope, forceIndexCreation, cancellationToken).ConfigureAwait(false); } - // report telemetry: - var totalTicks = Environment.TickCount - ticks; + var ticks = Environment.TickCount; - CompletionProvidersLogger.LogExtensionMethodCompletionTicksDataPoint(totalTicks); - CompletionProvidersLogger.LogExtensionMethodCompletionMethodsProvidedDataPoint(items.CompletionItems.Length); - CompletionProvidersLogger.LogExtensionMethodCompletionGetSymbolsTicksDataPoint(items.GetSymbolsTicks); - CompletionProvidersLogger.LogExtensionMethodCompletionCreateItemsTicksDataPoint(items.CreateItemsTicks); + var (items, counter) = await GetItemsAsync().ConfigureAwait(false); - if (items.IsPartialResult) - { - CompletionProvidersLogger.LogExtensionMethodCompletionPartialResultCount(); - } + counter.TotalTicks = Environment.TickCount - ticks; + counter.TotalExtensionMethodsProvided = items.Length; + counter.Report(); - return items.CompletionItems; + return items; } - public static async Task GetUnimportedExtensionMethodsInCurrentProcessAsync( + public static async Task<(ImmutableArray, StatisticCounter)> GetUnimportedExtensionMethodsInCurrentProcessAsync( Document document, int position, ITypeSymbol receiverTypeSymbol, @@ -87,6 +75,7 @@ public static async Task GetUnimportedEx bool forceIndexCreation, CancellationToken cancellationToken) { + var counter = new StatisticCounter(); var ticks = Environment.TickCount; // First find symbols of all applicable extension methods. @@ -95,7 +84,7 @@ public static async Task GetUnimportedEx document, position, receiverTypeSymbol, namespaceInScope, cancellationToken).ConfigureAwait(false); var (extentsionMethodSymbols, isPartialResult) = await symbolComputer.GetExtensionMethodSymbolsAsync(forceIndexCreation, cancellationToken).ConfigureAwait(false); - var getSymbolsTicks = Environment.TickCount - ticks; + counter.GetSymbolsTicks = Environment.TickCount - ticks; ticks = Environment.TickCount; var items = ConvertSymbolsToCompletionItems(extentsionMethodSymbols, cancellationToken); @@ -114,11 +103,13 @@ public static async Task GetUnimportedEx s_indexingTask = symbolComputer.PopulateIndicesAsync(CancellationToken.None); } } + + counter.PartialResult = true; } - var createItemsTicks = Environment.TickCount - ticks; + counter.CreateItemsTicks = Environment.TickCount - ticks; - return new SerializableUnimportedExtensionMethods(items, isPartialResult, getSymbolsTicks, createItemsTicks); + return (items, counter); } @@ -188,4 +179,26 @@ 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 6beb28a16c334..f80674e78bfea 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.Immutable; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Remote; @@ -13,12 +13,12 @@ namespace Microsoft.CodeAnalysis.Completion.Providers { internal interface IRemoteExtensionMethodImportCompletionService { - public ValueTask GetUnimportedExtensionMethodsAsync( + Task<(IList, StatisticCounter)> GetUnimportedExtensionMethodsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, string receiverTypeSymbolKeyData, - ImmutableArray namespaceInScope, + string[] 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 405e8e950b5d7..a6586b3ad1fc3 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableImportCompletionItem.cs @@ -4,29 +4,15 @@ #nullable enable -using System.Runtime.Serialization; - namespace Microsoft.CodeAnalysis.Completion.Providers { - [DataContract] internal readonly struct SerializableImportCompletionItem { - [DataMember(Order = 0)] public readonly string SymbolKeyData; - - [DataMember(Order = 1)] - public readonly string Name; - - [DataMember(Order = 2)] public readonly int Arity; - - [DataMember(Order = 3)] + public readonly string Name; 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 deleted file mode 100644 index f6c574acb8acc..0000000000000 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/SerializableUnimportedExtensionMethods.cs +++ /dev/null @@ -1,39 +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.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 94599f1a20489..2508ba8595e3a 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -168,22 +168,24 @@ public async Task ConvertToStructAsync( var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync( + var result = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteConvertTupleToStructCodeRefactoringProvider.ConvertToStructAsync), solution, - (service, solutionInfo, cancellationToken) => service.ConvertToStructAsync(solutionInfo, document.Id, span, scope, cancellationToken), + new object[] + { + document.Id, + span, + scope, + }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return solution; - } - var resultSolution = await RemoteUtilities.UpdateSolutionAsync( - solution, result.Value.DocumentTextChanges, cancellationToken).ConfigureAwait(false); + solution, result.DocumentTextChanges, cancellationToken).ConfigureAwait(false); return await AddRenameTokenAsync( - resultSolution, result.Value.RenamedToken, cancellationToken).ConfigureAwait(false); + resultSolution, result.RenamedToken, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs new file mode 100644 index 0000000000000..ddeaaab4772ae --- /dev/null +++ b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringProvider.cs @@ -0,0 +1,27 @@ +// 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 deleted file mode 100644 index c5c290b8826ea..0000000000000 --- a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs +++ /dev/null @@ -1,41 +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.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/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs index 1e375c4c10883..42ba15597de0a 100644 --- a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs @@ -31,12 +31,12 @@ protected AbstractDesignerAttributeIncrementalAnalyzer(Workspace workspace) _storageService = workspace.Services.GetRequiredService(); } - protected abstract ValueTask ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken); + protected abstract Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken); - protected abstract ValueTask ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken); + protected abstract Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken); public override Task RemoveProjectAsync(ProjectId projectId, CancellationToken cancellationToken) - => ReportProjectRemovedAsync(projectId, cancellationToken).AsTask(); + => ReportProjectRemovedAsync(projectId, cancellationToken); public override Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) => AnalyzeProjectAsync(project, specificDocument: null, cancellationToken); diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs index f301b126f4b97..935d6da138210 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs @@ -5,7 +5,6 @@ #nullable enable using System.Diagnostics; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Diagnostics @@ -13,7 +12,6 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// /// helper type to package diagnostic arguments to pass around between remote hosts /// - [DataContract] internal class DiagnosticArguments { /// @@ -22,41 +20,35 @@ 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; /// @@ -64,19 +56,16 @@ 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 new file mode 100644 index 0000000000000..5e5cd7f37eec5 --- /dev/null +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticResultSerializer.cs @@ -0,0 +1,308 @@ +// 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 60642c068f25f..3d794936fe037 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner.cs @@ -15,9 +15,7 @@ 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; @@ -142,10 +140,11 @@ private async Task FireAndForgetReportAnalyzerPerformanceAsync( // +1 for project itself var count = documentAnalysisScope != null ? 1 : project.DocumentIds.Count + 1; - var performanceInfo = analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(AnalyzerInfoCache).ToImmutableArray(); - - _ = await client.TryInvokeAsync( - (service, cancellationToken) => service.ReportAnalyzerPerformanceAsync(performanceInfo, count, cancellationToken), + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteDiagnosticAnalyzerService.ReportAnalyzerPerformance), + solution: null, + new object[] { analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(AnalyzerInfoCache), count }, callbackTarget: null, cancellationToken).ConfigureAwait(false); } @@ -194,40 +193,39 @@ private async Task( + return await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteDiagnosticAnalyzerService.CalculateDiagnosticsAsync), solution, - invocation: (service, solutionInfo, cancellationToken) => service.CalculateDiagnosticsAsync(solutionInfo, argument, cancellationToken), + new object[] { argument }, callbackTarget: null, + (s, c) => ReadCompilerAnalysisResultAsync(s, analyzerMap, documentAnalysisScope, project, c), cancellationToken).ConfigureAwait(false); + } - if (!result.HasValue) + private static async Task> 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: true, 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)) { return DiagnosticAnalysisResultMap.Empty; } - // 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)); + return result.Value; } - - // 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 2bfd5bf7fe1ec..3fc6e2e1e694a 100644 --- a/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/IRemoteDiagnosticAnalyzerService.cs @@ -4,9 +4,6 @@ using System; 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; @@ -15,25 +12,19 @@ namespace Microsoft.CodeAnalysis.Diagnostics { internal interface IRemoteDiagnosticAnalyzerService { - ValueTask CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, CancellationToken cancellationToken); - ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray snapshot, int unitCount, CancellationToken cancellationToken); + Task CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, string streamName, CancellationToken cancellationToken); + void ReportAnalyzerPerformance(List 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 a82808dd0be57..434cdc710fd55 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -30,18 +30,20 @@ public async Task> GetDocumentHighlightsAsync var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteDocumentHighlights.GetDocumentHighlightsAsync), solution, - (service, solutionInfo, cancellationToken) => service.GetDocumentHighlightsAsync(solutionInfo, document.Id, position, documentsToSearch.SelectAsArray(d => d.Id), cancellationToken), + new object[] + { + document.Id, + position, + documentsToSearch.Select(d => d.Id).ToArray() + }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return result.Value.SelectAsArray(h => h.Rehydrate(solution)); + return result.SelectAsArray(h => h.Rehydrate(solution)); } return await GetDocumentHighlightsInCurrentProcessAsync( @@ -98,6 +100,19 @@ 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, @@ -109,7 +124,7 @@ private async Task> GetTagsForReferencedSymbo { var progress = new StreamingProgressCollector(); - var options = FindSymbols.FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol); + var options = FindReferencesSearchOptions.GetFeatureOptionsForStartingSymbol(symbol); await SymbolFinder.FindReferencesAsync( symbol, document.Project.Solution, progress, documentsToSearch, options, cancellationToken).ConfigureAwait(false); @@ -149,7 +164,7 @@ private static bool ShouldConsiderSymbol(ISymbol symbol) private async Task> FilterAndCreateSpansAsync( ImmutableArray references, Document startingDocument, IImmutableSet documentsToSearch, ISymbol symbol, - FindSymbols.FindReferencesSearchOptions options, CancellationToken cancellationToken) + 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 9d49416dcbca8..ff50706ebc97c 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/IDocumentHighlightsService.cs @@ -3,7 +3,6 @@ // 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; @@ -19,13 +18,9 @@ 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 new file mode 100644 index 0000000000000..279a0b6359e35 --- /dev/null +++ b/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlights.cs @@ -0,0 +1,34 @@ +// 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 deleted file mode 100644 index 1a22573e933ce..0000000000000 --- a/src/Features/Core/Portable/DocumentHighlighting/IRemoteDocumentHighlightsService.cs +++ /dev/null @@ -1,42 +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.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 2fa6a0702b07d..6ebb8f0c51112 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 fieldSymbolKeys = fields.SelectAsArray(f => SymbolKey.CreateString(f, cancellationToken)); - - var result = await client.TryInvokeAsync)>>( + var result = await client.RunRemoteAsync<(DocumentId, TextChange[])[]>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteEncapsulateFieldService.EncapsulateFieldsAsync), solution, - (service, solutionInfo, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, document.Id, fieldSymbolKeys, updateReferences, cancellationToken), + new object[] + { + document.Id, + fields.Select(f => SymbolKey.CreateString(f, cancellationToken)).ToArray(), + updateReferences, + }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return solution; - } - return await RemoteUtilities.UpdateSolutionAsync( - solution, result.Value, cancellationToken).ConfigureAwait(false); + solution, result, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs index 8b7429f51a135..e1edfef47f965 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 { - ValueTask)>> EncapsulateFieldsAsync( + Task<(DocumentId, TextChange[])[]> EncapsulateFieldsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, ImmutableArray fieldSymbolKeys, diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs deleted file mode 100644 index e155e0ca31437..0000000000000 --- a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs +++ /dev/null @@ -1,234 +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.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 fc93cb930df8b..1e375b2f07cf2 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs @@ -38,13 +38,15 @@ public async Task> SearchDocumentAsync( { var solution = document.Project.Solution; - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteNavigateToSearchService.SearchDocumentAsync), solution, - (service, solutionInfo, cancellationToken) => service.SearchDocumentAsync(solutionInfo, document.Id, searchPattern, kinds.ToImmutableArray(), cancellationToken), + new object[] { document.Id, searchPattern, kinds.ToArray() }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value.SelectAsArray(r => r.Rehydrate(solution)) : ImmutableArray.Empty; + return result.SelectAsArray(r => r.Rehydrate(solution)); } return await SearchDocumentInCurrentProcessAsync( @@ -58,14 +60,16 @@ public async Task> SearchProjectAsync( if (client != null) { var solution = project.Solution; - var priorityDocumentIds = priorityDocuments.SelectAsArray(d => d.Id); - var result = await client.TryInvokeAsync>( + + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteNavigateToSearchService.SearchProjectAsync), solution, - (service, solutionInfo, cancellationToken) => service.SearchProjectAsync(solutionInfo, project.Id, priorityDocumentIds, searchPattern, kinds.ToImmutableArray(), cancellationToken), + new object[] { project.Id, priorityDocuments.Select(d => d.Id).ToArray(), searchPattern, kinds.ToArray() }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - return result.HasValue ? result.Value.SelectAsArray(r => r.Rehydrate(solution)) : ImmutableArray.Empty; + return result.SelectAsArray(r => r.Rehydrate(solution)); } return await SearchProjectInCurrentProcessAsync( diff --git a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs index 677c502aa2e95..7949a1bb3439c 100644 --- a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs @@ -2,9 +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. -#nullable enable - -using System.Collections.Immutable; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Remote; @@ -13,10 +11,10 @@ namespace Microsoft.CodeAnalysis.NavigateTo { internal interface IRemoteNavigateToSearchService { - ValueTask> SearchDocumentAsync( - PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, ImmutableArray kinds, CancellationToken cancellationToken); + Task> SearchDocumentAsync( + PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken); - ValueTask> SearchProjectAsync( - PinnedSolutionInfo solutionInfo, ProjectId projectId, ImmutableArray priorityDocumentIds, string searchPattern, ImmutableArray kinds, CancellationToken cancellationToken); + Task> SearchProjectAsync( + PinnedSolutionInfo solutionInfo, ProjectId projectId, DocumentId[] priorityDocumentIds, string searchPattern, string[] kinds, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/Remote/RemoteArguments.cs b/src/Features/Core/Portable/Remote/RemoteArguments.cs index 0cb7df7d1b282..75d2aaf12ac58 100644 --- a/src/Features/Core/Portable/Remote/RemoteArguments.cs +++ b/src/Features/Core/Portable/Remote/RemoteArguments.cs @@ -4,83 +4,50 @@ 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 - [DataContract] - internal readonly struct SerializableNavigateToSearchResult + internal class SerializableNavigateToSearchResult { - [DataMember(Order = 0)] - public readonly string AdditionalInformation; + public string AdditionalInformation; - [DataMember(Order = 1)] - public readonly string Kind; + public string Kind; + public NavigateToMatchKind MatchKind; + public bool IsCaseSensitive; + public string Name; + public IList NameMatchSpans; + public string SecondarySort; + public string Summary; - [DataMember(Order = 2)] - public readonly NavigateToMatchKind MatchKind; + public SerializableNavigableItem NavigableItem; - [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) + internal static SerializableNavigateToSearchResult Dehydrate(INavigateToSearchResult result) { - AdditionalInformation = additionalInformation; - Kind = kind; - MatchKind = matchKind; - IsCaseSensitive = isCaseSensitive; - Name = name; - NameMatchSpans = nameMatchSpans; - SecondarySort = secondarySort; - Summary = summary; - NavigableItem = 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) + }; } - 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, + Name, NameMatchSpans.ToImmutableArrayOrEmpty(), SecondarySort, Summary, NavigableItem.Rehydrate(solution)); } @@ -115,68 +82,42 @@ public NavigateToSearchResult( } } - /// - /// 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 + internal class SerializableNavigableItem { - [DataMember(Order = 0)] - public readonly Glyph Glyph; + public Glyph Glyph; - [DataMember(Order = 1)] - public readonly ImmutableArray DisplayTaggedParts; + public IList DisplayTaggedParts; - [DataMember(Order = 2)] - public readonly bool DisplayFileLocation; + public bool DisplayFileLocation; - [DataMember(Order = 3)] - public readonly bool IsImplicitlyDeclared; + public bool IsImplicitlyDeclared; - [DataMember(Order = 4)] - public readonly DocumentId Document; + public DocumentId Document; + public TextSpan SourceSpan; - [DataMember(Order = 5)] - public readonly TextSpan SourceSpan; + public IList ChildItems; - [DataMember(Order = 6)] - public readonly ImmutableArray ChildItems; - - public SerializableNavigableItem( - Glyph glyph, - ImmutableArray displayTaggedParts, - bool displayFileLocation, - bool isImplicitlyDeclared, - DocumentId document, - TextSpan sourceSpan, - ImmutableArray childItems) + public static SerializableNavigableItem Dehydrate(INavigableItem item) { - Glyph = glyph; - DisplayTaggedParts = displayTaggedParts; - DisplayFileLocation = displayFileLocation; - IsImplicitlyDeclared = isImplicitlyDeclared; - Document = document; - SourceSpan = sourceSpan; - ChildItems = 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) + }; } - 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, + Glyph, DisplayTaggedParts.ToImmutableArrayOrEmpty(), DisplayFileLocation, IsImplicitlyDeclared, solution.GetDocument(Document), SourceSpan, diff --git a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs index 83f521377233b..232374ff036e7 100644 --- a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentsIncrementalAnalyzer.cs @@ -25,7 +25,7 @@ protected AbstractTodoCommentsIncrementalAnalyzer() { } - protected abstract ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken); + protected abstract Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken); public override bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e) => e.Option == TodoCommentOptions.TokenList; @@ -33,7 +33,7 @@ public override bool NeedsReanalysisOnOptionChanged(object sender, OptionChanged public override Task RemoveDocumentAsync(DocumentId documentId, CancellationToken cancellationToken) { // Just report this back as there being no more comments for this document. - return ReportTodoCommentDataAsync(documentId, ImmutableArray.Empty, cancellationToken).AsTask(); + return ReportTodoCommentDataAsync(documentId, ImmutableArray.Empty, cancellationToken); } private ImmutableArray GetTodoCommentDescriptors(Document document) diff --git a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs index d552edcc199f0..029b47ac1cced 100644 --- a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs +++ b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs @@ -43,16 +43,18 @@ private TodoCommentData CreateSerializableData( var originalLineInfo = location.GetLineSpan(); var mappedLineInfo = location.GetMappedLineSpan(); - 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()); + 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(), + }; } public static async Task ConvertAsync( diff --git a/src/Interactive/HostProcess/InteractiveHost64.csproj b/src/Interactive/HostProcess/InteractiveHost64.csproj index 78d5253ea799c..db4710f3a78ee 100644 --- a/src/Interactive/HostProcess/InteractiveHost64.csproj +++ b/src/Interactive/HostProcess/InteractiveHost64.csproj @@ -5,7 +5,7 @@ false Exe - net472;net5.0 + net472;net5.0-windows win10-x64 true diff --git a/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj b/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj index 0808e3174338d..b60b76a252d6b 100644 --- a/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj +++ b/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj @@ -40,7 +40,7 @@ - TargetFramework=net5.0 + TargetFramework=net5.0-windows InteractiveHostFiles_Core diff --git a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs index dfa0c1a116312..00b358711f65c 100644 --- a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs +++ b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs @@ -199,19 +199,16 @@ 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 referenceCountOpt = await _callbackService.InvokeAsync( + var referenceCount = await _callbackService.InvokeAsync( _owner, nameof(ICodeLensContext.GetReferenceCountAsync), new object[] { Descriptor, descriptorContext }, cancellationToken).ConfigureAwait(false); - - if (!referenceCountOpt.HasValue) + if (referenceCount == null) { return null; } - var referenceCount = referenceCountOpt.Value; - var referenceCountString = $"{referenceCount.Count}{(referenceCount.IsCapped ? "+" : string.Empty)}"; return new CodeLensDataPointDescriptor() { @@ -223,7 +220,7 @@ public void Dispose() ImageId = null }; - static string GetCodeElementKindsString(CodeElementKinds kind) + string GetCodeElementKindsString(CodeElementKinds kind) { switch (kind) { @@ -245,53 +242,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 entries = referenceLocationDescriptors?.Select(referenceLocationDescriptor => + var details = new CodeLensDetailsDescriptor { - ImageId imageId = default; - if (referenceLocationDescriptor.Glyph.HasValue) + Headers = s_header, + Entries = referenceLocationDescriptors.Select(referenceLocationDescriptor => { - var moniker = referenceLocationDescriptor.Glyph.Value.GetImageMoniker(); - imageId = new ImageId(moniker.Guid, moniker.Id); - } + ImageId imageId = default; + if (referenceLocationDescriptor.Glyph.HasValue) + { + var moniker = referenceLocationDescriptor.Glyph.Value.GetImageMoniker(); + imageId = new ImageId(moniker.Guid, moniker.Id); + } - return new CodeLensDetailEntryDescriptor() - { - // use default since reference codelens don't require special behaviors - NavigationCommand = null, - NavigationCommandArgs = null, - Tooltip = null, - Fields = new List() + return new CodeLensDetailEntryDescriptor() { - 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 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(), // 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 4c94b7606eaa6..f0c322dd8f3ba 100644 --- a/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs +++ b/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs @@ -3,7 +3,6 @@ // 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; @@ -26,18 +25,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.HasValue || callerMethods.Value.IsEmpty) + if (callerMethods == null || !callerMethods.Any()) { return Empty; } - return callerMethods.Value.SelectAsArray(m => ( + return callerMethods.Select(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 b7eb9660005be..f1fac962d790f 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 553d7beceed41..afd05c09fc019 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 faa2c4bb96bf1..87558a9ea8021 100644 --- a/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs +++ b/src/VisualStudio/Core/Def/Implementation/CodeLens/RemoteCodeLensReferencesService.cs @@ -2,10 +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. -#nullable enable - using System.Collections.Generic; -using System.Collections.Immutable; using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading; @@ -15,7 +12,6 @@ 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; @@ -31,7 +27,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)) @@ -44,41 +40,36 @@ public RemoteCodeLensReferencesService() var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync( + return await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteCodeLensReferencesService.GetReferenceCountAsync), solution, - (service, solutionInfo, cancellationToken) => service.GetReferenceCountAsync(solutionInfo, documentId, syntaxNode.Span, maxSearchResults, cancellationToken), + new object[] { documentId, syntaxNode.Span, maxSearchResults }, 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.HasValue) + if (descriptors == null) { return null; } // map spans to right locations using SpanMapper for documents such as cshtml and etc - return await FixUpDescriptorsAsync(solution, descriptors.Value, cancellationToken).ConfigureAwait(false); + return await FixUpDescriptorsAsync(solution, descriptors, 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)) @@ -91,20 +82,20 @@ public RemoteCodeLensReferencesService() var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync?>( + return await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteCodeLensReferencesService.FindReferenceMethodsAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindReferenceMethodsAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken), + new object[] { documentId, syntaxNode.Span }, 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)) @@ -117,35 +108,31 @@ public RemoteCodeLensReferencesService() var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync( + return await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteCodeLensReferencesService.GetFullyQualifiedNameAsync), solution, - (service, solutionInfo, cancellationToken) => service.GetFullyQualifiedNameAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken), + new object[] { documentId, syntaxNode.Span }, 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, ImmutableArray descriptors, CancellationToken cancellationToken) + private static async Task> FixUpDescriptorsAsync( + Solution solution, IEnumerable descriptors, CancellationToken cancellationToken) { - using var _ = ArrayBuilder.GetInstance(out var list); + var list = new 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 @@ -195,7 +182,7 @@ private static async Task> FixUpDesc after2)); } - return list.ToImmutable(); + return list; } private static (string text, int start, int length) GetReferenceInfo(ExcerptResult? reference, ReferenceLocationDescriptor descriptor) @@ -239,24 +226,24 @@ private static string GetLineTextOrEmpty(TextLineCollection lines, int index) return lines[index].ToString().TrimEnd(); } - private static async Task?> FindReferenceLocationsWorkerAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, + private async Task> FindReferenceLocationsWorkerAsync(Solution solution, DocumentId documentId, SyntaxNode syntaxNode, CancellationToken cancellationToken) { if (syntaxNode == null) { - return ImmutableArray.Empty; + return null; } var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync?>( + return await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteCodeLensReferencesService.FindReferenceLocationsAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindReferenceLocationsAsync(solutionInfo, documentId, syntaxNode.Span, cancellationToken), + new object[] { documentId, syntaxNode.Span }, 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/InProcDesignerAttributeIncrementalAnalyzer.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs index f44a4a3185987..7ae9157b36202 100644 --- a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs +++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/InProcDesignerAttributeIncrementalAnalyzer.cs @@ -21,10 +21,10 @@ public InProcDesignerAttributeIncrementalAnalyzer(Workspace workspace, IDesigner _listener = listener; } - protected override ValueTask ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) + protected override Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) => _listener.OnProjectRemovedAsync(projectId, cancellationToken); - protected override ValueTask ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken) + protected override Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken) => _listener.ReportDesignerAttributeDataAsync(data.ToImmutableArray(), cancellationToken); } } diff --git a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs index b00ce35c3a9a5..a7e9094795047 100644 --- a/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs +++ b/src/VisualStudio/Core/Def/Implementation/DesignerAttribute/VisualStudioDesignerAttributeService.cs @@ -31,7 +31,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribu { [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared] internal class VisualStudioDesignerAttributeService - : ForegroundThreadAffinitizedObject, IDesignerAttributeListener, IEventListener, IDisposable + : ForegroundThreadAffinitizedObject, IDesignerAttributeListener, IEventListener { private readonly VisualStudioWorkspaceImpl _workspace; @@ -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? _connection; /// /// Cache from project to the CPS designer service for it. Computed on demand (which @@ -80,11 +80,6 @@ public VisualStudioDesignerAttributeService( ThreadingContext.DisposalToken); } - public void Dispose() - { - _lazyConnection?.Dispose(); - } - void IEventListener.StartListening(Workspace workspace, object _) { if (workspace is VisualStudioWorkspace) @@ -123,12 +118,15 @@ 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); + _connection = await client.CreateConnectionAsync( + WellKnownServiceHubService.RemoteDesignerAttributeService, + 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. - _ = await _lazyConnection.TryInvokeAsync( - (service, cancellationToken) => service.StartScanningForDesignerAttributesAsync(cancellationToken), + await _connection.RunRemoteAsync( + nameof(IRemoteDesignerAttributeService.StartScanningForDesignerAttributesAsync), + solution: null, + arguments: Array.Empty(), cancellationToken).ConfigureAwait(false); } @@ -334,17 +332,17 @@ private async Task NotifyCpsProjectSystemAsync( /// /// Callback from the OOP service back into us. /// - public ValueTask ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken) + public Task ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken) { Contract.ThrowIfNull(_workQueue); _workQueue.AddWork(data); - return new ValueTask(); + return Task.CompletedTask; } - public ValueTask OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) + public Task OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) { _cpsProjects.TryRemove(projectId, out _); - return new ValueTask(); + return Task.CompletedTask; } } } diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs b/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs index 33c38ab72590d..80bdccadd9be9 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs @@ -26,7 +26,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectTelemetr { [ExportEventListener(WellKnownEventListeners.Workspace, WorkspaceKind.Host), Shared] internal class VisualStudioProjectTelemetryService - : ForegroundThreadAffinitizedObject, IProjectTelemetryListener, IEventListener, IDisposable + : ForegroundThreadAffinitizedObject, IProjectTelemetryListener, IEventListener { private const string EventPrefix = "VS/Compilers/Compilation/"; private const string PropertyPrefix = "VS.Compilers.Compilation.Inputs."; @@ -49,7 +49,7 @@ internal class VisualStudioProjectTelemetryService /// 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? _connection; /// /// Queue where we enqueue the information we get from OOP to process in batch in the future. @@ -70,11 +70,6 @@ public VisualStudioProjectTelemetryService( threadingContext.DisposalToken); } - public void Dispose() - { - _lazyConnection?.Dispose(); - } - void IEventListener.StartListening(Workspace workspace, object _) { if (workspace is VisualStudioWorkspace) @@ -110,12 +105,15 @@ 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); + _connection = await client.CreateConnectionAsync( + WellKnownServiceHubService.RemoteProjectTelemetryService, + 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. - _ = await _lazyConnection.TryInvokeAsync( - (service, cancellationToken) => service.ComputeProjectTelemetryAsync(cancellationToken), + await _connection.RunRemoteAsync( + nameof(IRemoteProjectTelemetryService.ComputeProjectTelemetryAsync), + solution: null, + arguments: Array.Empty(), cancellationToken).ConfigureAwait(false); } @@ -186,11 +184,11 @@ private void NotifyTelemetryService(ProjectTelemetryData info) /// /// Callback from the OOP service back into us. /// - public ValueTask ReportProjectTelemetryDataAsync(ProjectTelemetryData info, CancellationToken cancellationToken) + public Task ReportProjectTelemetryDataAsync(ProjectTelemetryData info, CancellationToken cancellationToken) { Contract.ThrowIfNull(_workQueue); _workQueue.AddWork(info); - return new ValueTask(); + return Task.CompletedTask; } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs b/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs index 3342fc93a8e45..778e1caf7f1ba 100644 --- a/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/VisualStudioRemoteHostClientProvider.cs @@ -6,17 +6,13 @@ using System; using System.Composition; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Telemetry; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.ServiceBroker; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Remote @@ -26,13 +22,10 @@ internal sealed class VisualStudioRemoteHostClientProvider : IRemoteHostClientPr [ExportWorkspaceServiceFactory(typeof(IRemoteHostClientProvider), WorkspaceKind.Host), Shared] internal sealed class Factory : IWorkspaceServiceFactory { - private readonly IAsyncServiceProvider _vsServiceProvider; - [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public Factory(SVsServiceProvider vsServiceProvider) + public Factory() { - _vsServiceProvider = (IAsyncServiceProvider)vsServiceProvider; } [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] @@ -45,42 +38,23 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) return new DefaultRemoteHostClientProvider(); } - return new VisualStudioRemoteHostClientProvider(workspaceServices, _vsServiceProvider); + return new VisualStudioRemoteHostClientProvider(workspaceServices); } } private readonly HostWorkspaceServices _services; - private readonly AsyncLazy _lazyClient; - private readonly IAsyncServiceProvider _vsServiceProvider; + private readonly AsyncLazy _lazyClient; - private VisualStudioRemoteHostClientProvider(HostWorkspaceServices services, IAsyncServiceProvider vsServiceProvider) + private VisualStudioRemoteHostClientProvider(HostWorkspaceServices services) { _services = services; - _vsServiceProvider = vsServiceProvider; - _lazyClient = new AsyncLazy(CreateHostClientAsync, cacheResult: true); + _lazyClient = new AsyncLazy(CreateHostClientAsync, cacheResult: true); } - private async Task CreateHostClientAsync(CancellationToken cancellationToken) - { - try - { - var brokeredServiceContainer = await _vsServiceProvider.GetServiceAsync().ConfigureAwait(false); - var serviceBroker = brokeredServiceContainer.GetFullAccessServiceBroker(); - - var client = await ServiceHubRemoteHostClient.CreateAsync(_services, serviceBroker, cancellationToken).ConfigureAwait(false); - - // proffer in-proc brokered services: - _ = brokeredServiceContainer.Proffer(SolutionAssetProvider.ServiceDescriptor, (_, _, _, _) => new ValueTask(new SolutionAssetProvider(_services))); - - return client; - } - catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e)) - { - return null; - } - } + private Task CreateHostClientAsync(CancellationToken cancellationToken) + => ServiceHubRemoteHostClient.CreateAsync(_services, cancellationToken); public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken) - => _lazyClient.GetValueAsync(cancellationToken); + => _lazyClient.GetValueAsync(cancellationToken).AsNullable(); } } diff --git a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/SemanticClassificationCacheIncrementalAnalyzerProvider.cs b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/SemanticClassificationCacheIncrementalAnalyzerProvider.cs index 7271307836773..6c05e78dda477 100644 --- a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/SemanticClassificationCacheIncrementalAnalyzerProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/SemanticClassificationCacheIncrementalAnalyzerProvider.cs @@ -64,9 +64,11 @@ public override async Task AnalyzeDocumentAsync(Document document, SyntaxNode bo var isFullyLoaded = await statusService.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false); Debug.Assert(isFullyLoaded, "We should only be called by the incremental analyzer once the solution is fully loaded."); - await client.TryInvokeAsync( + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSemanticClassificationCacheService.CacheSemanticClassificationsAsync), document.Project.Solution, - (service, solutionInfo, cancellationToken) => service.CacheSemanticClassificationsAsync(solutionInfo, document.Id, isFullyLoaded, cancellationToken), + arguments: new object[] { document.Id, isFullyLoaded }, callbackTarget: null, cancellationToken).ConfigureAwait(false); } diff --git a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs index 6131db8b2e3ef..300464c1434ca 100644 --- a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs +++ b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs @@ -52,16 +52,18 @@ public async Task> GetCachedSemanticClassificatio return default; } - var classifiedSpans = await client.TryInvokeAsync( - (service, cancellationToken) => service.GetCachedSemanticClassificationsAsync(documentKey.Dehydrate(), textSpan, checksum, cancellationToken), + var classifiedSpans = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSemanticClassificationCacheService.GetCachedSemanticClassificationsAsync), + solution: null, + arguments: new object[] { documentKey.Dehydrate(), textSpan, checksum }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - - if (!classifiedSpans.HasValue || classifiedSpans.Value == null) + if (classifiedSpans == null) return default; var list = ClassificationUtilities.GetOrCreateClassifiedSpanList(); - classifiedSpans.Value.Rehydrate(list); + classifiedSpans.Rehydrate(list); var result = list.ToImmutableArray(); ClassificationUtilities.ReturnClassifiedSpanList(list); diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs index d45ae2064b25b..ffced79472572 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/InProcTodoCommentsIncrementalAnalyzer.cs @@ -19,7 +19,7 @@ internal sealed class InProcTodoCommentsIncrementalAnalyzer : AbstractTodoCommen public InProcTodoCommentsIncrementalAnalyzer(ITodoCommentsListener listener) => _listener = listener; - protected override ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) + protected override Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) => _listener.ReportTodoCommentDataAsync(documentId, data, cancellationToken); } } diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs index 895aeec7bc1c8..e6f1a976e85d1 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs @@ -36,8 +36,7 @@ internal class VisualStudioTodoCommentsService ITodoCommentsListener, ITodoListProvider, IVsTypeScriptTodoCommentService, - IEventListener, - IDisposable + IEventListener { private readonly VisualStudioWorkspaceImpl _workspace; private readonly EventListenerTracker _eventListenerTracker; @@ -46,10 +45,10 @@ private readonly ConcurrentDictionary>(); /// - /// Remote service connection. Created on demand when we startup and then + /// Our connections 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? _connection; /// /// Queue where we enqueue the information we get from OOP to process in batch in the future. @@ -71,11 +70,6 @@ public VisualStudioTodoCommentsService( _eventListenerTracker = new EventListenerTracker(eventListeners, WellKnownEventListeners.TodoListProvider); } - public void Dispose() - { - _lazyConnection?.Dispose(); - } - void IEventListener.StartListening(Workspace workspace, object _) { if (workspace is VisualStudioWorkspace) @@ -120,15 +114,18 @@ 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); + _connection = await client.CreateConnectionAsync( + WellKnownServiceHubService.RemoteTodoCommentsService, + 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); // 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. - _ = await _lazyConnection.TryInvokeAsync( - (service, cancellationToken) => service.ComputeTodoCommentsAsync(cancellationToken), + await _connection.RunRemoteAsync( + nameof(IRemoteTodoCommentsService.ComputeTodoCommentsAsync), + solution: null, + arguments: Array.Empty(), cancellationToken).ConfigureAwait(false); } @@ -221,18 +218,10 @@ public IEnumerable GetTodoItemsUpdatedEventArgs( /// /// Callback from the OOP service back into us. /// - public async ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray infos, CancellationToken cancellationToken) + public async Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray infos, CancellationToken cancellationToken) { - try - { - var workQueue = await _workQueueSource.Task.ConfigureAwait(false); - workQueue.AddWork(new DocumentAndComments(documentId, infos)); - } - catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceledAndPropagate(e)) - { - // report NFW before returning back to the remote process - throw ExceptionUtilities.Unreachable; - } + var workQueue = await _workQueueSource.Task.ConfigureAwait(false); + workQueue.AddWork(new DocumentAndComments(documentId, infos)); } /// diff --git a/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs b/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs index e51c5e7179a6c..d6c7e06cbd236 100644 --- a/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs +++ b/src/VisualStudio/Core/Def/Implementation/Watson/WatsonReporter.cs @@ -208,8 +208,7 @@ private static List CollectServiceHubLogFilePaths() // name our services more consistently to simplify filtering // filter logs that are not relevant to Roslyn investigation - if (!name.Contains("-" + ServiceDescriptors.ServiceNamePrefix) && - !name.Contains("-" + RemoteServiceName.Prefix) && + if (!name.Contains("-" + RemoteServiceName.Prefix) && !name.Contains("-" + RemoteServiceName.IntelliCodeServiceName) && !name.Contains("-" + RemoteServiceName.RazorServiceName) && !name.Contains("-" + RemoteServiceName.UnitTestingAnalysisServiceName) && diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs index 8a6be3647de88..d5583833880c3 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.LogService.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.VisualStudio.Shell.Interop; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { @@ -25,23 +26,23 @@ public LogService(IThreadingContext threadingContext, IVsActivityLog activityLog _activityLog = activityLog; } - public ValueTask LogInfoAsync(string text, CancellationToken cancellationToken) + public Task LogInfoAsync(string text) => LogAsync(text, __ACTIVITYLOG_ENTRYTYPE.ALE_INFORMATION); - public ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken) + public Task LogExceptionAsync(string exception, string text) => LogAsync(text + ". " + exception, __ACTIVITYLOG_ENTRYTYPE.ALE_ERROR); - private ValueTask LogAsync(string text, __ACTIVITYLOG_ENTRYTYPE type) + private Task LogAsync(string text, __ACTIVITYLOG_ENTRYTYPE type) { Log(text, type); - return default; + return Task.CompletedTask; } private void Log(string text, __ACTIVITYLOG_ENTRYTYPE type) { - if (!IsForeground()) + if (!this.IsForeground()) { - InvokeBelowInputPriorityAsync(() => Log(text, type)); + this.InvokeBelowInputPriorityAsync(() => Log(text, type)); return; } diff --git a/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/VisualStudioSymbolSearchService.cs index 05295bdd9cd66..1c0b5be7ac4ef 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, ThreadingContext.DisposalToken)); + Task.Run(() => UpdateSourceInBackgroundAsync(SymbolSearchUpdateEngine.NugetOrgSource)); } private async Task GetEngineAsync(CancellationToken cancellationToken) @@ -89,13 +89,13 @@ private async Task GetEngineAsync(CancellationToken c } } - private async Task UpdateSourceInBackgroundAsync(string sourceName, CancellationToken cancellationToken) + private async Task UpdateSourceInBackgroundAsync(string sourceName) { - var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); - await engine.UpdateContinuouslyAsync(sourceName, _localSettingsDirectory, cancellationToken).ConfigureAwait(false); + var engine = await GetEngineAsync(this.ThreadingContext.DisposalToken).ConfigureAwait(false); + await engine.UpdateContinuouslyAsync(sourceName, _localSettingsDirectory).ConfigureAwait(false); } - public async ValueTask> FindPackagesWithTypeAsync( + public async Task> FindPackagesWithTypeAsync( string source, string name, int arity, CancellationToken cancellationToken) { var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); @@ -105,7 +105,7 @@ public async ValueTask> FindPackagesWithTy return FilterAndOrderPackages(allPackagesWithType); } - public async ValueTask> FindPackagesWithAssemblyAsync( + public async Task> 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 ValueTask> FindReferenceAssembliesWithTypeAsync( + public async Task> FindReferenceAssembliesWithTypeAsync( string name, int arity, CancellationToken cancellationToken) { var engine = await GetEngineAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Core/Test.Next/Mocks/SimpleAssetSource.cs b/src/VisualStudio/Core/Test.Next/Mocks/SimpleAssetSource.cs index 9fffcbef61a33..40acf2fc4ea0a 100644 --- a/src/VisualStudio/Core/Test.Next/Mocks/SimpleAssetSource.cs +++ b/src/VisualStudio/Core/Test.Next/Mocks/SimpleAssetSource.cs @@ -25,7 +25,7 @@ public SimpleAssetSource(IReadOnlyDictionary map) _map = map; } - public ValueTask> GetAssetsAsync( + public Task> GetAssetsAsync( int serviceId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) { var results = new List<(Checksum, object)>(); @@ -42,10 +42,10 @@ public SimpleAssetSource(IReadOnlyDictionary map) } } - return new ValueTask>(results.ToImmutableArray()); + return Task.FromResult(results.ToImmutableArray()); } - public ValueTask IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) - => new ValueTask(false); + public Task IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) + => SpecializedTasks.False; } } diff --git a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs index cb9cd2ab96322..a0a8660271e02 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs @@ -76,10 +76,12 @@ public async Task TestSessionWithNoSolution() var mock = new MockLogService(); var client = await service.TryGetRemoteHostClientAsync(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)); + 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); } [Fact] @@ -150,8 +152,8 @@ public Assembly LoadFromPath(string fullPath) private class MockLogService : ISymbolSearchLogService { - public ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken) => default; - public ValueTask LogInfoAsync(string text, CancellationToken cancellationToken) => default; + public Task LogExceptionAsync(string exception, string text) => Task.CompletedTask; + public Task LogInfoAsync(string text) => Task.CompletedTask; } } } diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index db7c6216f43f7..8f996de07515c 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -138,10 +138,15 @@ public async Task TestTodoComments() var cancellationTokenSource = new CancellationTokenSource(); - using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token); + using var connection = await client.CreateConnectionAsync( + WellKnownServiceHubService.RemoteTodoCommentsService, + callback, + cancellationTokenSource.Token); - var invokeTask = connection.TryInvokeAsync( - (service, cancellationToken) => service.ComputeTodoCommentsAsync(cancellationToken), + var invokeTask = connection.RunRemoteAsync( + nameof(IRemoteTodoCommentsService.ComputeTodoCommentsAsync), + solution: null, + arguments: Array.Empty(), cancellationTokenSource.Token); var data = await callback.Data; @@ -149,20 +154,22 @@ 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(); - Assert.True(await invokeTask); + await invokeTask; } private class TodoCommentsListener : ITodoCommentsListener @@ -171,10 +178,10 @@ private class TodoCommentsListener : ITodoCommentsListener = new TaskCompletionSource<(DocumentId, ImmutableArray)>(); public Task<(DocumentId, ImmutableArray)> Data => _dataSource.Task; - public ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) + public Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) { _dataSource.SetResult((documentId, data)); - return new ValueTask(); + return Task.CompletedTask; } } @@ -214,10 +221,15 @@ public async Task TestDesignerAttributes() var callback = new DesignerAttributeListener(); - using var connection = await client.CreateConnectionAsync(callback, cancellationTokenSource.Token); + using var connection = await client.CreateConnectionAsync( + WellKnownServiceHubService.RemoteDesignerAttributeService, + callback, + cancellationTokenSource.Token); - var invokeTask = connection.TryInvokeAsync( - (service, cancellationToken) => service.StartScanningForDesignerAttributesAsync(cancellationToken), + var invokeTask = connection.RunRemoteAsync( + nameof(IRemoteDesignerAttributeService.StartScanningForDesignerAttributesAsync), + solution: null, + arguments: Array.Empty(), cancellationTokenSource.Token); var infos = await callback.Infos; @@ -229,7 +241,7 @@ public async Task TestDesignerAttributes() cancellationTokenSource.Cancel(); - Assert.True(await invokeTask); + await invokeTask; } private class DesignerAttributeListener : IDesignerAttributeListener @@ -238,13 +250,13 @@ private readonly TaskCompletionSource> _in = new TaskCompletionSource>(); public Task> Infos => _infosSource.Task; - public ValueTask OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) - => new ValueTask(); + public Task OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) + => Task.CompletedTask; - public ValueTask ReportDesignerAttributeDataAsync(ImmutableArray infos, CancellationToken cancellationToken) + public Task ReportDesignerAttributeDataAsync(ImmutableArray infos, CancellationToken cancellationToken) { _infosSource.SetResult(infos); - return new ValueTask(); + return Task.CompletedTask; } } diff --git a/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb index 382b984035ce4..9a96accafd5eb 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(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") + 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"} } provider.RaiseTodoListUpdated(workspace) @@ -270,8 +270,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Dim snapshot1 = factory.GetCurrentSnapshot() provider.Items = New TodoCommentData() { - 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") + 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"} } provider.RaiseTodoListUpdated(workspace) @@ -360,16 +360,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Sub Private Function CreateItem(documentId As DocumentId) As TodoCommentData - Return New TodoCommentData( - priority:=0, - message:="test", - documentId:=documentId, - mappedLine:=10, - originalLine:=10, - mappedColumn:=20, - originalColumn:=20, - mappedFilePath:=Nothing, - originalFilePath:="test1") + Return New TodoCommentData With { + .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 cefc8fe99a6b2..d5f83e815a2a2 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, cancellationToken As CancellationToken) As ValueTask Implements ISymbolSearchLogService.LogExceptionAsync - Return Nothing + Public Function LogExceptionAsync(exception As String, text As String) As Task Implements ISymbolSearchLogService.LogExceptionAsync + Return Task.CompletedTask End Function - Public Function LogInfoAsync(text As String, cancellationToken As CancellationToken) As ValueTask Implements ISymbolSearchLogService.LogInfoAsync - Return Nothing + Public Function LogInfoAsync(text As String) As Task Implements ISymbolSearchLogService.LogInfoAsync + Return Task.CompletedTask 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 301008f464ee7..1252f492cbecd 100644 --- a/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb +++ b/src/VisualStudio/Core/Test/Venus/DocumentService_IntegrationTests.vb @@ -143,7 +143,6 @@ 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() @@ -153,7 +152,7 @@ class {|Definition:C1|} Dim actual = New List(Of (String, LinePosition, String)) - For Each result In results.Value + For Each result In results actual.Add((result.FilePath, New LinePosition(result.LineNumber, result.ColumnNumber), result.ReferenceLineText)) Next diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj index 9f06a0e91b7c4..bd80e1adfb702 100644 --- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj +++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj @@ -269,7 +269,7 @@ InteractiveHost.Core64 - TargetFramework=net5.0 + TargetFramework=net5.0-windows true false diff --git a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs index 290699d2f7fcb..838df901664a0 100644 --- a/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/AbstractClassificationService.cs @@ -44,28 +44,35 @@ public async Task AddSemanticClassificationsAsync(Document document, TextSpan te return; } + var remoteSuccess = await TryAddSemanticClassificationsInRemoteProcessAsync( + document, textSpan, result, cancellationToken).ConfigureAwait(false); + if (remoteSuccess) + return; + + using var _ = ArrayBuilder.GetInstance(out var temp); + await AddSemanticClassificationsInCurrentProcessAsync( + document, textSpan, temp, cancellationToken).ConfigureAwait(false); + AddRange(temp, result); + } + + /// if the remote call was made successfully and we should + /// use the results of it. Otherwise, fall back to processing locally + private static async Task TryAddSemanticClassificationsInRemoteProcessAsync(Document document, TextSpan textSpan, List result, CancellationToken cancellationToken) + { var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); - if (client != null) - { - var classifiedSpans = await client.TryInvokeAsync( - document.Project.Solution, - (service, solutionInfo, cancellationToken) => service.GetSemanticClassificationsAsync(solutionInfo, document.Id, textSpan, cancellationToken), - callbackTarget: null, - cancellationToken).ConfigureAwait(false); - - // if the remote call fails do nothing (error has already been reported) - if (classifiedSpans.HasValue) - { - classifiedSpans.Value.Rehydrate(result); - } - } - else - { - using var _ = ArrayBuilder.GetInstance(out var temp); - await AddSemanticClassificationsInCurrentProcessAsync( - document, textSpan, temp, cancellationToken).ConfigureAwait(false); - AddRange(temp, result); - } + if (client == null) + return false; + + var classifiedSpans = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSemanticClassificationService.GetSemanticClassificationsAsync), + document.Project.Solution, + new object[] { document.Id, textSpan }, + callbackTarget: null, + cancellationToken).ConfigureAwait(false); + + classifiedSpans.Rehydrate(result); + return true; } public static async Task AddSemanticClassificationsInCurrentProcessAsync(Document document, TextSpan textSpan, ArrayBuilder result, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs index 1fc45f2df836d..8365601411429 100644 --- a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs +++ b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Classification /// internal interface IRemoteSemanticClassificationCacheService { - ValueTask CacheSemanticClassificationsAsync( + Task CacheSemanticClassificationsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, bool isFullyLoaded, CancellationToken cancellationToken); /// @@ -27,7 +27,7 @@ ValueTask CacheSemanticClassificationsAsync( /// /// Pass in . This will ensure that the cached /// classifications are only returned if they match the content the file currently has. - ValueTask GetCachedSemanticClassificationsAsync( + Task GetCachedSemanticClassificationsAsync( SerializableDocumentKey documentKey, TextSpan textSpan, Checksum checksum, diff --git a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs index 4017dfb785d5d..4a96e58bcaacb 100644 --- a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationService.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; @@ -18,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Classification { internal interface IRemoteSemanticClassificationService { - ValueTask GetSemanticClassificationsAsync( + Task GetSemanticClassificationsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, CancellationToken cancellationToken); } @@ -27,13 +26,9 @@ 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 a364fad975817..c6600938ce0ed 100644 --- a/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs +++ b/src/Workspaces/Core/Portable/DesignerAttribute/DesignerAttributeData.cs @@ -4,32 +4,26 @@ #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/IDesignerAttributeListener.cs b/src/Workspaces/Core/Portable/DesignerAttribute/IDesignerAttributeListener.cs index a2341af3cde8b..17f9e31c9df1e 100644 --- a/src/Workspaces/Core/Portable/DesignerAttribute/IDesignerAttributeListener.cs +++ b/src/Workspaces/Core/Portable/DesignerAttribute/IDesignerAttributeListener.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.DesignerAttribute /// internal interface IDesignerAttributeListener { - ValueTask OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken); - ValueTask ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken); + Task OnProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken); + Task ReportDesignerAttributeDataAsync(ImmutableArray data, CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs b/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs similarity index 77% rename from src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs rename to src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs index d6a1c90950d69..fcc902b58d196 100644 --- a/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeDiscoveryService.cs +++ b/src/Workspaces/Core/Portable/DesignerAttribute/IRemoteDesignerAttributeService.cs @@ -13,8 +13,8 @@ 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 IRemoteDesignerAttributeDiscoveryService + internal interface IRemoteDesignerAttributeService { - ValueTask StartScanningForDesignerAttributesAsync(CancellationToken cancellation); + Task StartScanningForDesignerAttributesAsync(CancellationToken cancellation); } } diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs index 4fd86b4dd0966..907f2d85ec29d 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.Runtime.Serialization; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -22,64 +23,32 @@ 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 8a3715b98cee5..b4e00bf899551 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticDataLocation.cs @@ -4,56 +4,33 @@ #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 deleted file mode 100644 index f13422cecdc79..0000000000000 --- a/src/Workspaces/Core/Portable/Diagnostics/SerializableDiagnosticAnalysisResultMap.cs +++ /dev/null @@ -1,62 +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.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/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs index b174ba2b210f3..2226c881f907c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs @@ -41,18 +41,15 @@ public static async Task> FindAllDeclarationsWithNormalQ { var solution = project.Solution; - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindAllDeclarationsWithNormalQueryAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindAllDeclarationsWithNormalQueryAsync(solutionInfo, project.Id, query.Name, query.Kind, criteria, cancellationToken), - callbackTarget: SymbolFinder.EmptyServerCallback.Instance, + new object[] { project.Id, query.Name, query.Kind, criteria }, + callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(solution, result, 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 8ef1520ff603a..50bab9639d6de 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs @@ -44,18 +44,15 @@ public static async Task> FindSourceDeclarationsWithNorm var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithNormalQueryAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindSolutionSourceDeclarationsWithNormalQueryAsync(solutionInfo, name, ignoreCase, criteria, cancellationToken), - callbackTarget: SymbolFinder.EmptyServerCallback.Instance, + new object[] { name, ignoreCase, criteria }, + callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false); } return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( @@ -83,18 +80,15 @@ public static async Task> FindSourceDeclarationsWithNorm var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithNormalQueryAsync), project.Solution, - (service, solutionInfo, cancellationToken) => service.FindProjectSourceDeclarationsWithNormalQueryAsync(solutionInfo, project.Id, name, ignoreCase, criteria, cancellationToken), - callbackTarget: SymbolFinder.EmptyServerCallback.Instance, + new object[] { project.Id, name, ignoreCase, criteria }, + callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return await RehydrateAsync(project.Solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(project.Solution, result, cancellationToken).ConfigureAwait(false); } return await FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( @@ -117,18 +111,15 @@ public static async Task> FindSourceDeclarationsWithPatt var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithPatternAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindSolutionSourceDeclarationsWithPatternAsync(solutionInfo, pattern, criteria, cancellationToken), - callbackTarget: SymbolFinder.EmptyServerCallback.Instance, + new object[] { pattern, criteria }, + callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false); } return await FindSourceDeclarationsWithPatternInCurrentProcessAsync( @@ -151,18 +142,15 @@ public static async Task> FindSourceDeclarationsWithPatt var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); if (client != null) { - var result = await client.TryInvokeAsync>( + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithPatternAsync), project.Solution, - (service, solutionInfo, cancellationToken) => service.FindProjectSourceDeclarationsWithPatternAsync(solutionInfo, project.Id, pattern, criteria, cancellationToken), - callbackTarget: SymbolFinder.EmptyServerCallback.Instance, + new object[] { project.Id, pattern, criteria }, + callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (!result.HasValue) - { - return ImmutableArray.Empty; - } - - return await RehydrateAsync(project.Solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(project.Solution, result, 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 13f3de4b0392d..8ce7208f93db0 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 0d1610aa035f7..8087a7201385d 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedClasses.cs @@ -8,22 +8,45 @@ 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, HashSet set) + static bool TypeMatches(INamedTypeSymbol type, SymbolSet 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 2968cb04f7031..83c69d9b29e8f 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_DerivedInterfaces.cs @@ -13,19 +13,41 @@ 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, HashSet set) + static bool TypeMatches(INamedTypeSymbol type, SymbolSet 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 97b4288b65f85..fb5da99be31f5 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs @@ -8,15 +8,38 @@ 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) { @@ -36,7 +59,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, HashSet set) + static bool TypeMatches(INamedTypeSymbol type, SymbolSet 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 79c01bc5faec3..516b9899a347c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_Remote.cs @@ -4,7 +4,6 @@ #nullable enable -using System; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -12,75 +11,46 @@ 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> FindTypesAsync( + public static async Task?> TryFindRemoteTypesAsync( INamedTypeSymbol type, Solution solution, - IImmutableSet? projects, + IImmutableSet projects, bool transitive, - DependentTypesKind kind, + FunctionId functionId, + string remoteFunctionName, CancellationToken cancellationToken) { - if (SerializableSymbolAndProjectId.TryCreate(type, solution, cancellationToken, out var serializedType)) + using (Logger.LogBlock(functionId, cancellationToken)) { - var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); - if (client != null) + if (SerializableSymbolAndProjectId.TryCreate(type, solution, cancellationToken, out var serializedType)) { - 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); - - if (!result.HasValue) + var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); + if (client != null) { - return ImmutableArray.Empty; - } + var result = await client.RunRemoteAsync>( + WellKnownServiceHubService.CodeAnalysis, + remoteFunctionName, + solution, + new object?[] + { + serializedType, + projects?.Select(p => p.Id).ToArray(), + transitive, + }, + null, + cancellationToken).ConfigureAwait(false); - return await RehydrateAsync(solution, result.Value, cancellationToken).ConfigureAwait(false); + return await RehydrateAsync(solution, result, cancellationToken).ConfigureAwait(false); + } } - - // TODO: Do not fall back to in-proc https://github.com/dotnet/roslyn/issues/47557 } - 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); - } + return null; } 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 deleted file mode 100644 index 0a87cbfc930c2..0000000000000 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypesKind.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.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 82c8473e56ab1..cb0779667f234 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 ValueTask HandleLocationAsync(ISymbol symbol, ReferenceLocation location) + private Task 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 5553edcac308c..c7b4b56426f88 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchOptions.cs @@ -2,13 +2,11 @@ // 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 { - [DataContract] - internal sealed class FindReferencesSearchOptions + internal class FindReferencesSearchOptions { public static readonly FindReferencesSearchOptions Default = new FindReferencesSearchOptions( @@ -27,14 +25,12 @@ internal sealed 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 new file mode 100644 index 0000000000000..0c019db1d97db --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinder.cs @@ -0,0 +1,35 @@ +// 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 deleted file mode 100644 index 476787d2bd7ea..0000000000000 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/IRemoteDependentTypeFinderService.cs +++ /dev/null @@ -1,22 +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 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 aed4162ab5821..065d32c831e9c 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 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; + 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; private class NoOpProgressTracker : IStreamingProgressTracker { - public ValueTask AddItemsAsync(int count) => default; - public ValueTask ItemCompletedAsync() => default; + public Task AddItemsAsync(int count) => Task.CompletedTask; + public Task ItemCompletedAsync() => Task.CompletedTask; } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/StreamingFindReferencesProgress.cs index 9c662202a1412..c9e46f9d5e03b 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; - ProgressTracker = new StreamingProgressTracker((current, max) => + this.ProgressTracker = new StreamingProgressTracker((current, max) => { _progress.ReportProgress(current, max); - return default; + return Task.CompletedTask; }); } - public ValueTask OnCompletedAsync() + public Task OnCompletedAsync() { _progress.OnCompleted(); - return default; + return Task.CompletedTask; } - public ValueTask OnDefinitionFoundAsync(ISymbol symbol) + public Task OnDefinitionFoundAsync(ISymbol symbol) { _progress.OnDefinitionFound(symbol); - return default; + return Task.CompletedTask; } - public ValueTask OnFindInDocumentCompletedAsync(Document document) + public Task OnFindInDocumentCompletedAsync(Document document) { _progress.OnFindInDocumentCompleted(document); - return default; + return Task.CompletedTask; } - public ValueTask OnFindInDocumentStartedAsync(Document document) + public Task OnFindInDocumentStartedAsync(Document document) { _progress.OnFindInDocumentStarted(document); - return default; + return Task.CompletedTask; } - public ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location) + public Task OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location) { _progress.OnReferenceFound(symbol, location); - return default; + return Task.CompletedTask; } - public ValueTask OnStartedAsync() + public Task OnStartedAsync() { _progress.OnStarted(); - return default; + return Task.CompletedTask; } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs new file mode 100644 index 0000000000000..24169be4667a2 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinder.cs @@ -0,0 +1,35 @@ +// 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 deleted file mode 100644 index 16eb7e98718aa..0000000000000 --- a/src/Workspaces/Core/Portable/FindSymbols/IRemoteSymbolFinderService.cs +++ /dev/null @@ -1,49 +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; -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 8f69f00766c8c..d05e6732d9104 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; } - ValueTask OnStartedAsync(); - ValueTask OnCompletedAsync(); + Task OnStartedAsync(); + Task OnCompletedAsync(); - ValueTask OnFindInDocumentStartedAsync(Document document); - ValueTask OnFindInDocumentCompletedAsync(Document document); + Task OnFindInDocumentStartedAsync(Document document); + Task OnFindInDocumentCompletedAsync(Document document); - ValueTask OnDefinitionFoundAsync(ISymbol symbol); - ValueTask OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location); + Task OnDefinitionFoundAsync(ISymbol symbol); + Task OnReferenceFoundAsync(ISymbol symbol, ReferenceLocation location); } internal interface IStreamingFindLiteralReferencesProgress { IStreamingProgressTracker ProgressTracker { get; } - ValueTask OnReferenceFoundAsync(Document document, TextSpan span); + Task OnReferenceFoundAsync(Document document, TextSpan span); } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs index 5187ad6dc79a1..fb3bf5876c39f 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 ValueTask OnStartedAsync() => _underlyingProgress.OnStartedAsync(); - public ValueTask OnCompletedAsync() => _underlyingProgress.OnCompletedAsync(); + public Task OnStartedAsync() => _underlyingProgress.OnStartedAsync(); + public Task OnCompletedAsync() => _underlyingProgress.OnCompletedAsync(); - public ValueTask OnFindInDocumentCompletedAsync(Document document) => _underlyingProgress.OnFindInDocumentCompletedAsync(document); - public ValueTask OnFindInDocumentStartedAsync(Document document) => _underlyingProgress.OnFindInDocumentStartedAsync(document); + public Task OnFindInDocumentCompletedAsync(Document document) => _underlyingProgress.OnFindInDocumentCompletedAsync(document); + public Task OnFindInDocumentStartedAsync(Document document) => _underlyingProgress.OnFindInDocumentStartedAsync(document); - public ValueTask OnDefinitionFoundAsync(ISymbol definition) + public Task OnDefinitionFoundAsync(ISymbol definition) { lock (_gate) { @@ -69,7 +69,7 @@ public ValueTask OnDefinitionFoundAsync(ISymbol definition) return _underlyingProgress.OnDefinitionFoundAsync(definition); } - public ValueTask OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location) + public Task OnReferenceFoundAsync(ISymbol definition, ReferenceLocation location) { lock (_gate) { diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.EmptyServerCallback.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.EmptyServerCallback.cs deleted file mode 100644 index 3d2b513140eac..0000000000000 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.EmptyServerCallback.cs +++ /dev/null @@ -1,50 +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.Tasks; -using Microsoft.CodeAnalysis.Remote; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.FindSymbols -{ - public static partial class SymbolFinder - { - internal sealed class EmptyServerCallback : IRemoteSymbolFinderService.ICallback - { - public static readonly EmptyServerCallback Instance = new(); - - private EmptyServerCallback() - { - } - - public ValueTask AddItemsAsync(int count) - => throw ExceptionUtilities.Unreachable; - - public ValueTask ItemCompletedAsync() - => throw ExceptionUtilities.Unreachable; - - public ValueTask OnLiteralReferenceFoundAsync(DocumentId documentId, TextSpan span) - => throw ExceptionUtilities.Unreachable; - - 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.FindLiteralsServerCallback.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs index 08ff7c0808362..fe4999b7874ef 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindLiteralsServerCallback.cs @@ -3,15 +3,13 @@ // 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 : IRemoteSymbolFinderService.ICallback + internal sealed class FindLiteralsServerCallback { private readonly Solution _solution; private readonly IStreamingFindLiteralReferencesProgress _progress; @@ -24,35 +22,18 @@ public FindLiteralsServerCallback( _progress = progress; } - public ValueTask AddItemsAsync(int count) + public Task AddItemsAsync(int count) => _progress.ProgressTracker.AddItemsAsync(count); - public ValueTask ItemCompletedAsync() + public Task ItemCompletedAsync() => _progress.ProgressTracker.ItemCompletedAsync(); - public async ValueTask OnLiteralReferenceFoundAsync(DocumentId documentId, TextSpan span) + public async Task OnReferenceFoundAsync( + 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 781bcabbe7f80..656c0c0599f33 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder.FindReferencesServerCallback.cs @@ -6,8 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Remote; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols { @@ -17,7 +15,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 : IRemoteSymbolFinderService.ICallback, IEqualityComparer + internal sealed class FindReferencesServerCallback : IEqualityComparer { private readonly Solution _solution; private readonly IStreamingFindReferencesProgress _progress; @@ -37,25 +35,25 @@ public FindReferencesServerCallback( _definitionMap = new Dictionary(this); } - public ValueTask AddItemsAsync(int count) => _progress.ProgressTracker.AddItemsAsync(count); - public ValueTask ItemCompletedAsync() => _progress.ProgressTracker.ItemCompletedAsync(); + public Task AddItemsAsync(int count) => _progress.ProgressTracker.AddItemsAsync(count); + public Task ItemCompletedAsync() => _progress.ProgressTracker.ItemCompletedAsync(); - public ValueTask OnStartedAsync() => _progress.OnStartedAsync(); - public ValueTask OnCompletedAsync() => _progress.OnCompletedAsync(); + public Task OnStartedAsync() => _progress.OnStartedAsync(); + public Task OnCompletedAsync() => _progress.OnCompletedAsync(); - public ValueTask OnFindInDocumentStartedAsync(DocumentId documentId) + public Task OnFindInDocumentStartedAsync(DocumentId documentId) { var document = _solution.GetDocument(documentId); return _progress.OnFindInDocumentStartedAsync(document); } - public ValueTask OnFindInDocumentCompletedAsync(DocumentId documentId) + public Task OnFindInDocumentCompletedAsync(DocumentId documentId) { var document = _solution.GetDocument(documentId); return _progress.OnFindInDocumentCompletedAsync(document); } - public async ValueTask OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition) + public async Task OnDefinitionFoundAsync(SerializableSymbolAndProjectId definition) { var symbol = await definition.TryRehydrateAsync( _solution, _cancellationToken).ConfigureAwait(false); @@ -71,7 +69,7 @@ public async ValueTask OnDefinitionFoundAsync(SerializableSymbolAndProjectId def await _progress.OnDefinitionFoundAsync(symbol).ConfigureAwait(false); } - public async ValueTask OnReferenceFoundAsync( + public async Task OnReferenceFoundAsync( SerializableSymbolAndProjectId definition, SerializableReferenceLocation reference) { ISymbol symbol; @@ -99,9 +97,6 @@ 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 5095a860c5867..e7b0da751212b 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindLiteralReferences.cs @@ -29,9 +29,11 @@ internal static async Task FindLiteralReferencesAsync( // the 'progress' parameter which will then update the UI. var serverCallback = new FindLiteralsServerCallback(solution, progress); - _ = await client.TryInvokeAsync( + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindLiteralReferencesAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindLiteralReferencesAsync(solutionInfo, value, typeCode, cancellationToken), + new object[] { value, typeCode }, 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 8fcb8ca396f7f..397e278440eff 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_FindReferences_Current.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Remote; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols { @@ -38,11 +37,17 @@ 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.TryInvokeAsync( + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteSymbolFinder.FindReferencesAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindReferencesAsync(solutionInfo, serializedSymbol, documentIds, options, cancellationToken), + new object[] + { + serializedSymbol, + documents?.Select(d => d.Id).ToArray(), + SerializableFindReferencesSearchOptions.Dehydrate(options), + }, 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 bb4c53c42e339..7a2922d5c79e8 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.FindTypesAsync( - type, solution, projects, transitive, DependentTypesKind.DerivedClasses, cancellationToken).ConfigureAwait(false); + var types = await DependentTypeFinder.FindDerivedClassesAsync( + type, solution, projects, transitive, 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.FindTypesAsync( - type, solution, projects, transitive, DependentTypesKind.DerivedInterfaces, cancellationToken).ConfigureAwait(false); + var types = await DependentTypeFinder.FindDerivedInterfacesAsync( + type, solution, projects, transitive, 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.FindTypesAsync( - type, solution, projects, transitive, DependentTypesKind.ImplementingTypes, cancellationToken).ConfigureAwait(false); + var types = await DependentTypeFinder.FindImplementingTypesAsync( + type, solution, projects, transitive, cancellationToken).ConfigureAwait(false); return types.WhereAsArray(t => IsAccessible(t)); } diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj index 6c10dd4c92f98..e4a8abe955557 100644 --- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj @@ -25,7 +25,6 @@ - diff --git a/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs b/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs index 8c68787296e5d..0ab4460adf21e 100644 --- a/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs +++ b/src/Workspaces/Core/Portable/Packaging/IPackageInstallerService.cs @@ -5,7 +5,6 @@ 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; @@ -43,13 +42,9 @@ bool TryInstallPackage(Workspace workspace, DocumentId documentId, event EventHandler PackageSourcesChanged; } - [DataContract] - internal readonly struct PackageSource : IEquatable + internal struct PackageSource : IEquatable { - [DataMember(Order = 0)] public readonly string Name; - - [DataMember(Order = 1)] public readonly string Source; public PackageSource(string name, string source) @@ -59,7 +54,7 @@ public PackageSource(string name, string source) } public override bool Equals(object obj) - => obj is PackageSource source && Equals(source); + => Equals((PackageSource)obj); public bool Equals(PackageSource other) => Name == other.Name && Source == other.Source; diff --git a/src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryListener.cs b/src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryListener.cs index 963470a043496..df0f87f5cb0b4 100644 --- a/src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryListener.cs +++ b/src/Workspaces/Core/Portable/ProjectTelemetry/IProjectTelemetryListener.cs @@ -15,6 +15,6 @@ namespace Microsoft.CodeAnalysis.ProjectTelemetry /// internal interface IProjectTelemetryListener { - ValueTask ReportProjectTelemetryDataAsync(ProjectTelemetryData data, CancellationToken cancellationToken); + Task ReportProjectTelemetryDataAsync(ProjectTelemetryData data, CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs b/src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs index 65ebdea33b289..2a16ef3cbedee 100644 --- a/src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs +++ b/src/Workspaces/Core/Portable/ProjectTelemetry/IRemoteProjectTelemetryService.cs @@ -15,6 +15,6 @@ namespace Microsoft.CodeAnalysis.ProjectTelemetry /// internal interface IRemoteProjectTelemetryService { - ValueTask ComputeProjectTelemetryAsync(CancellationToken cancellation); + Task ComputeProjectTelemetryAsync(CancellationToken cancellation); } } diff --git a/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs b/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs index b5a83c34538e8..b4a2a628f9db2 100644 --- a/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs +++ b/src/Workspaces/Core/Portable/ProjectTelemetry/ProjectTelemetryData.cs @@ -4,47 +4,20 @@ #nullable enable -using System.Runtime.Serialization; - namespace Microsoft.CodeAnalysis.ProjectTelemetry { /// /// Serialization typed used to pass information to/from OOP and VS. /// - [DataContract] - internal readonly struct ProjectTelemetryData + internal struct ProjectTelemetryData { - [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 ProjectId ProjectId; + public string Language; + public int AnalyzerReferencesCount; + public int ProjectReferencesCount; + public int MetadataReferencesCount; + public int DocumentsCount; + public int AdditionalDocumentsCount; public bool Equals(ProjectTelemetryData other) => Language.Equals(other.Language) && diff --git a/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs b/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs index c4a3ccb289e00..3c292fe7b6487 100644 --- a/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs +++ b/src/Workspaces/Core/Portable/Remote/PinnedSolutionInfo.cs @@ -4,14 +4,11 @@ #nullable enable -using System.Runtime.Serialization; - namespace Microsoft.CodeAnalysis.Remote { /// /// Information related to pinned solution /// - [DataContract] internal sealed class PinnedSolutionInfo { /// @@ -19,7 +16,6 @@ internal sealed class PinnedSolutionInfo /// /// This later used to find matching solution between VS and remote host /// - [DataMember(Order = 0)] public readonly int ScopeId; /// @@ -28,17 +24,14 @@ 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 2befbad3917ba..1bb740910dc6d 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteArguments.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Immutable; -using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; @@ -16,20 +15,32 @@ namespace Microsoft.CodeAnalysis.Remote { #region FindReferences - [DataContract] - internal sealed class SerializableSymbolAndProjectId + internal class SerializableFindReferencesSearchOptions { - [DataMember(Order = 0)] - public readonly string SymbolKeyData; + public bool AssociatePropertyReferencesWithSpecificAccessor; + public bool Cascade; - [DataMember(Order = 1)] - public readonly ProjectId ProjectId; + public static SerializableFindReferencesSearchOptions Dehydrate(FindReferencesSearchOptions options) + { + return new SerializableFindReferencesSearchOptions + { + AssociatePropertyReferencesWithSpecificAccessor = options.AssociatePropertyReferencesWithSpecificAccessor, + Cascade = options.Cascade, + }; + } - public SerializableSymbolAndProjectId(string symbolKeyData, ProjectId projectId) + public FindReferencesSearchOptions Rehydrate() { - SymbolKeyData = symbolKeyData; - ProjectId = projectId; + return new FindReferencesSearchOptions( + associatePropertyReferencesWithSpecificAccessor: AssociatePropertyReferencesWithSpecificAccessor, + cascade: Cascade); } + } + + internal class SerializableSymbolAndProjectId + { + public string SymbolKeyData; + public ProjectId ProjectId; public static SerializableSymbolAndProjectId Dehydrate( IAliasSymbol alias, Document document, CancellationToken cancellationToken) @@ -49,7 +60,11 @@ public static SerializableSymbolAndProjectId Dehydrate( } public static SerializableSymbolAndProjectId Create(ISymbol symbol, Project project, CancellationToken cancellationToken) - => new(symbol.GetSymbolKey(cancellationToken).ToString(), project.Id); + => new SerializableSymbolAndProjectId + { + SymbolKeyData = symbol.GetSymbolKey(cancellationToken).ToString(), + ProjectId = project.Id, + }; public static bool TryCreate( ISymbol symbol, Solution solution, CancellationToken cancellationToken, @@ -75,7 +90,11 @@ public static bool TryCreate( return false; } - result = new SerializableSymbolAndProjectId(SymbolKey.CreateString(symbol, cancellationToken), project.Id); + result = new SerializableSymbolAndProjectId + { + SymbolKeyData = SymbolKey.CreateString(symbol, cancellationToken), + ProjectId = project.Id, + }; return true; } public async Task TryRehydrateAsync( @@ -107,59 +126,83 @@ public async Task TryRehydrateAsync( } } - [DataContract] - internal readonly struct SerializableReferenceLocation + internal class SerializableSymbolUsageInfo : IEquatable { - [DataMember(Order = 0)] - public readonly DocumentId Document; + 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 = 1)] - public readonly SerializableSymbolAndProjectId Alias; + public SymbolUsageInfo Rehydrate() + { + return IsValueUsageInfo + ? SymbolUsageInfo.Create((ValueUsageInfo)UsageInfoUnderlyingValue) + : SymbolUsageInfo.Create((TypeOrNamespaceUsageInfo)UsageInfoUnderlyingValue); + } - [DataMember(Order = 2)] - public readonly TextSpan Location; + public bool Equals(SerializableSymbolUsageInfo other) + { + return other != null && + IsValueUsageInfo == other.IsValueUsageInfo && + UsageInfoUnderlyingValue == other.UsageInfoUnderlyingValue; + } - [DataMember(Order = 3)] - public readonly bool IsImplicit; + public override bool Equals(object obj) + => Equals(obj as SerializableSymbolUsageInfo); - [DataMember(Order = 4)] - public readonly SymbolUsageInfo SymbolUsageInfo; + public override int GetHashCode() + => Hash.Combine(IsValueUsageInfo.GetHashCode(), UsageInfoUnderlyingValue.GetHashCode()); + } - [DataMember(Order = 5)] - public readonly ImmutableDictionary AdditionalProperties; + internal class SerializableReferenceLocation + { + public DocumentId Document { get; set; } - [DataMember(Order = 6)] - public readonly CandidateReason CandidateReason; + public SerializableSymbolAndProjectId Alias { 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 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 static SerializableReferenceLocation Dehydrate( ReferenceLocation referenceLocation, CancellationToken cancellationToken) { - return new SerializableReferenceLocation( - referenceLocation.Document.Id, - SerializableSymbolAndProjectId.Dehydrate(referenceLocation.Alias, referenceLocation.Document, cancellationToken), - referenceLocation.Location.SourceSpan, - referenceLocation.IsImplicit, - referenceLocation.SymbolUsageInfo, - referenceLocation.AdditionalProperties, - referenceLocation.CandidateReason); + 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 + }; } public async Task RehydrateAsync( @@ -174,7 +217,7 @@ public async Task RehydrateAsync( aliasSymbol, CodeAnalysis.Location.Create(syntaxTree, Location), isImplicit: IsImplicit, - symbolUsageInfo: SymbolUsageInfo, + symbolUsageInfo: SymbolUsageInfo.Rehydrate(), additionalProperties: additionalProperties ?? ImmutableDictionary.Empty, candidateReason: CandidateReason); } diff --git a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs index 806a7d45472c7..bf1d8ad67a216 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.IO.Pipelines; using System.Threading; using System.Threading.Tasks; using Roslyn.Utilities; @@ -59,72 +58,8 @@ private void OnStatusChanged(bool started) return service.TryGetRemoteHostClientAsync(cancellationToken); } - public abstract ValueTask> CreateConnectionAsync(object? callbackTarget, CancellationToken cancellationToken) - where T : class; - public abstract Task CreateConnectionAsync(RemoteServiceName serviceName, object? callbackTarget, CancellationToken cancellationToken); - // brokered services: - - public async ValueTask TryInvokeAsync( - Func invocation, - object? callbackTarget, - CancellationToken cancellationToken) - where TService : class - { - using var connection = await CreateConnectionAsync(callbackTarget, cancellationToken).ConfigureAwait(false); - return await connection.TryInvokeAsync(invocation, cancellationToken).ConfigureAwait(false); - } - - public async ValueTask> TryInvokeAsync( - Func> invocation, - object? callbackTarget, - CancellationToken cancellationToken) - where TService : class - { - using var connection = await CreateConnectionAsync(callbackTarget, cancellationToken).ConfigureAwait(false); - return await connection.TryInvokeAsync(invocation, cancellationToken).ConfigureAwait(false); - } - - public async ValueTask TryInvokeAsync( - Solution solution, - Func invocation, - object? callbackTarget, - CancellationToken cancellationToken) - where TService : class - { - using var connection = await CreateConnectionAsync(callbackTarget, cancellationToken).ConfigureAwait(false); - return await connection.TryInvokeAsync(solution, invocation, cancellationToken).ConfigureAwait(false); - } - - public async ValueTask> TryInvokeAsync( - Solution solution, - Func> invocation, - object? callbackTarget, - CancellationToken cancellationToken) - where TService : class - { - using var connection = await CreateConnectionAsync(callbackTarget, cancellationToken).ConfigureAwait(false); - return await connection.TryInvokeAsync(solution, invocation, cancellationToken).ConfigureAwait(false); - } - - /// - /// Invokes a remote API that streams data back to the caller via a pipe. - /// - public async ValueTask> TryInvokeAsync( - Solution solution, - Func invocation, - Func> reader, - object? callbackTarget, - CancellationToken cancellationToken) - where TService : class - { - using var connection = await CreateConnectionAsync(callbackTarget, cancellationToken).ConfigureAwait(false); - return await connection.TryInvokeAsync(solution, invocation, reader, cancellationToken).ConfigureAwait(false); - } - - // legacy services: - public async Task RunRemoteAsync(RemoteServiceName serviceName, string targetName, Solution? solution, IReadOnlyList arguments, object? callbackTarget, CancellationToken cancellationToken) { using var connection = await CreateConnectionAsync(serviceName, callbackTarget, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/Remote/RemoteServiceConnection.cs b/src/Workspaces/Core/Portable/Remote/RemoteServiceConnection.cs index 620bb2bbe4cbe..6517bad1bd762 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteServiceConnection.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteServiceConnection.cs @@ -7,15 +7,11 @@ using System; using System.Collections.Generic; using System.IO; -using System.IO.Pipelines; using System.Threading; using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Remote { - /// - /// Abstracts a connection to a legacy remote service. - /// internal abstract class RemoteServiceConnection : IDisposable { public abstract void Dispose(); @@ -26,43 +22,4 @@ internal abstract class RemoteServiceConnection : IDisposable public Task RunRemoteAsync(string targetName, Solution? solution, IReadOnlyList arguments, CancellationToken cancellationToken) => RunRemoteAsync(targetName, solution, arguments, dataReader: null, cancellationToken); } - - /// - /// Abstracts a connection to a service implementing type . - /// - /// Remote interface type of the service. - internal abstract class RemoteServiceConnection : IDisposable - where TService : class - { - public abstract void Dispose(); - - public abstract ValueTask TryInvokeAsync( - Func invocation, - CancellationToken cancellationToken); - - public abstract ValueTask> TryInvokeAsync( - Func> invocation, - CancellationToken cancellationToken); - - public abstract ValueTask> TryInvokeAsync( - Func invocation, - Func> reader, - CancellationToken cancellationToken); - - public abstract ValueTask TryInvokeAsync( - Solution solution, - Func invocation, - CancellationToken cancellationToken); - - public abstract ValueTask> TryInvokeAsync( - Solution solution, - Func> invocation, - CancellationToken cancellationToken); - - public abstract ValueTask> TryInvokeAsync( - Solution solution, - Func invocation, - Func> reader, - CancellationToken cancellationToken); - } } diff --git a/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs b/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs index 51955fcac88c5..86e3893df01ad 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteServiceName.cs @@ -19,7 +19,6 @@ namespace Microsoft.CodeAnalysis.Remote internal readonly struct RemoteServiceName : IEquatable { internal const string Prefix = "roslyn"; - internal const string Suffix64 = "64"; internal const string IntelliCodeServiceName = "pythia"; internal const string RazorServiceName = "razorLanguageService"; internal const string UnitTestingAnalysisServiceName = "UnitTestingAnalysis"; @@ -46,10 +45,22 @@ public RemoteServiceName(string customServiceName) public string ToString(bool isRemoteHost64Bit) { + const string Suffix64 = "64"; + return CustomServiceName ?? (WellKnownService, isRemoteHost64Bit) switch { (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.RemoteDesignerAttributeService, false) => Prefix + nameof(WellKnownServiceHubService.RemoteDesignerAttributeService), + (WellKnownServiceHubService.RemoteDesignerAttributeService, true) => Prefix + nameof(WellKnownServiceHubService.RemoteDesignerAttributeService) + Suffix64, + (WellKnownServiceHubService.RemoteProjectTelemetryService, false) => Prefix + nameof(WellKnownServiceHubService.RemoteProjectTelemetryService), + (WellKnownServiceHubService.RemoteProjectTelemetryService, true) => Prefix + nameof(WellKnownServiceHubService.RemoteProjectTelemetryService) + Suffix64, + (WellKnownServiceHubService.RemoteTodoCommentsService, false) => Prefix + nameof(WellKnownServiceHubService.RemoteTodoCommentsService), + (WellKnownServiceHubService.RemoteTodoCommentsService, true) => Prefix + nameof(WellKnownServiceHubService.RemoteTodoCommentsService) + 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 69667ac1e81c5..6397763589adc 100644 --- a/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs +++ b/src/Workspaces/Core/Portable/Remote/RemoteUtilities.cs @@ -2,7 +2,6 @@ // 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; @@ -18,12 +17,12 @@ internal static class RemoteUtilities /// the set of document text changes necessary to convert to . /// - public static async ValueTask)>> GetDocumentTextChangesAsync( + public static async Task<(DocumentId, TextChange[])[]> GetDocumentTextChangesAsync( Solution oldSolution, Solution newSolution, CancellationToken cancellationToken) { - using var _ = ArrayBuilder<(DocumentId, ImmutableArray)>.GetInstance(out var builder); + using var _ = ArrayBuilder<(DocumentId, TextChange[])>.GetInstance(out var builder); var solutionChanges = newSolution.GetChanges(oldSolution); foreach (var projectChange in solutionChanges.GetProjectChanges()) @@ -33,11 +32,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.ToImmutableArray())); + builder.Add((docId, textChanges.ToArray())); } } - return builder.ToImmutable(); + return builder.ToArray(); } /// @@ -45,7 +44,7 @@ internal static class RemoteUtilities /// a solution textually equivalent to the newSolution passed to . /// public static async Task UpdateSolutionAsync( - Solution oldSolution, ImmutableArray<(DocumentId, ImmutableArray)> documentTextChanges, CancellationToken cancellationToken) + Solution oldSolution, (DocumentId, TextChange[])[] 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 d162ce804315f..c8634a328580e 100644 --- a/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs +++ b/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubService.cs @@ -8,20 +8,20 @@ namespace Microsoft.CodeAnalysis.Remote { internal enum WellKnownServiceHubService { - None = 0, - RemoteHost = 1, - // obsolete: CodeAnalysis = 2, - // obsolete: RemoteSymbolSearchUpdateService = 3, - // obsolete: RemoteDesignerAttributeService = 4, - // obsolete: RemoteProjectTelemetryService = 5, - // obsolete: RemoteTodoCommentsService = 6, - LanguageServer = 7, - IntelliCode = 8, - Razor = 9, + None, + RemoteHost, + CodeAnalysis, + RemoteSymbolSearchUpdateEngine, + RemoteDesignerAttributeService, + RemoteProjectTelemetryService, + RemoteTodoCommentsService, + LanguageServer, + IntelliCode, + Razor, // owned by Unit Testing team: - UnitTestingAnalysisService = 10, - LiveUnitTestingBuildService = 11, - UnitTestingSourceLookupService = 12, + UnitTestingAnalysisService, + LiveUnitTestingBuildService, + UnitTestingSourceLookupService, } } diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs index a807d161e7a35..25dfd69e333ca 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ComplexifiedSpan.cs @@ -3,21 +3,14 @@ // 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 3e69d9e7aad5d..be0f2f98c4695 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs @@ -52,19 +52,21 @@ internal static async Task ResolveConflictsAsync( var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var serializableLocationSet = renameLocationSet.Dehydrate(solution, cancellationToken); - var nonConflictSymbolIds = nonConflictSymbols?.SelectAsArray(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)) ?? default; - - var result = await client.TryInvokeAsync( + var result = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteRenamer.ResolveConflictsAsync), solution, - (service, solutionInfo, cancellationToken) => service.ResolveConflictsAsync(solutionInfo, serializableLocationSet, replacementText, nonConflictSymbolIds, cancellationToken), + new object?[] + { + renameLocationSet.Dehydrate(solution, cancellationToken), + replacementText, + nonConflictSymbols?.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(), + }, callbackTarget: null, 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) + if (result != null) + return await result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs index 29a5b5c52d530..6474f170706af 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/RelatedLocation.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Rename.ConflictEngine @@ -12,39 +11,30 @@ 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) { - ConflictCheckSpan = conflictCheckSpan; - Type = type; - IsReference = isReference; - DocumentId = documentId; - ComplexifiedTargetSpan = complexifiedTargetSpan; + this.ConflictCheckSpan = conflictCheckSpan; + this.Type = type; + this.IsReference = isReference; + this.DocumentId = documentId; + this.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 new file mode 100644 index 0000000000000..bc907c60a8921 --- /dev/null +++ b/src/Workspaces/Core/Portable/Rename/IRemoteRenamer.cs @@ -0,0 +1,300 @@ +// 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 deleted file mode 100644 index 8141d4047fbe6..0000000000000 --- a/src/Workspaces/Core/Portable/Rename/IRemoteRenamerService.cs +++ /dev/null @@ -1,367 +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.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 d8f46cdcf6e01..2c1ece38c04ab 100644 --- a/src/Workspaces/Core/Portable/Rename/RenameLocations.cs +++ b/src/Workspaces/Core/Portable/Rename/RenameLocations.cs @@ -62,6 +62,47 @@ 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. /// @@ -80,24 +121,26 @@ public static async Task FindLocationsAsync( var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var options = SerializableRenameOptionSet.Dehydrate(optionSet); - - var result = await client.TryInvokeAsync( + var result = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteRenamer.FindRenameLocationsAsync), solution, - (service, solutionInfo, cancellationToken) => service.FindRenameLocationsAsync(solutionInfo, serializedSymbol, options, cancellationToken), + new object[] + { + serializedSymbol, + SerializableRenameOptionSet.Dehydrate(optionSet), + }, callbackTarget: null, cancellationToken).ConfigureAwait(false); - if (result.HasValue && result.Value != null) + if (result != null) { - var rehydrated = await TryRehydrateAsync( - solution, result.Value, cancellationToken).ConfigureAwait(false); + var rehydrated = await RenameLocations.TryRehydrateAsync( + solution, result, 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 c192cf019736c..9af151b77fc0d 100644 --- a/src/Workspaces/Core/Portable/Rename/Renamer.cs +++ b/src/Workspaces/Core/Portable/Rename/Renamer.cs @@ -127,25 +127,22 @@ internal static async Task RenameSymbolAsync( var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false); if (client != null) { - var options = SerializableRenameOptionSet.Dehydrate(optionSet); - var nonConflictSymbolIds = nonConflictSymbols?.SelectAsArray(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)) ?? default; - - var result = await client.TryInvokeAsync( + var result = await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteRenamer.RenameSymbolAsync), solution, - (service, solutionInfo, cancellationToken) => service.RenameSymbolAsync( - solutionInfo, + new object?[] + { serializedSymbol, newName, - options, - nonConflictSymbolIds, - cancellationToken), + SerializableRenameOptionSet.Dehydrate(optionSet), + nonConflictSymbols?.Select(s => SerializableSymbolAndProjectId.Dehydrate(solution, s, cancellationToken)).ToArray(), + }, callbackTarget: null, 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) + if (result != null) + return await result.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/IStreamingProgressTracker.cs index cea0381877f5e..37088d4b1609e 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 { - ValueTask AddItemsAsync(int count); - ValueTask ItemCompletedAsync(); + Task AddItemsAsync(int count); + Task ItemCompletedAsync(); } } diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs index ec673f6cc912f..7e4be62ec4407 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/StreamingProgressTracker.cs @@ -2,8 +2,6 @@ // 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; @@ -13,36 +11,41 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities /// /// Utility class that can be used to track the progress of an operation in a threadsafe manner. /// - internal sealed class StreamingProgressTracker : IStreamingProgressTracker + internal class StreamingProgressTracker : IStreamingProgressTracker { private int _completedItems; private int _totalItems; - private readonly Func? _updateAction; + private readonly Func _updateActionOpt; + + public StreamingProgressTracker() + : this(null) + { + } - public StreamingProgressTracker(Func? updateAction = null) - => _updateAction = updateAction; + public StreamingProgressTracker(Func updateActionOpt) + => _updateActionOpt = updateActionOpt; - public ValueTask AddItemsAsync(int count) + public Task AddItemsAsync(int count) { Interlocked.Add(ref _totalItems, count); return UpdateAsync(); } - public ValueTask ItemCompletedAsync() + public Task ItemCompletedAsync() { Interlocked.Increment(ref _completedItems); return UpdateAsync(); } - private ValueTask UpdateAsync() + private Task UpdateAsync() { - if (_updateAction == null) + if (_updateActionOpt == null) { - return default; + return Task.CompletedTask; } - return _updateAction(_completedItems, _totalItems); + return _updateActionOpt(_completedItems, _totalItems); } } } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs index 88a3c952e654d..09255a5cfd178 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/IRemoteSymbolSearchUpdateEngine.cs @@ -2,17 +2,18 @@ // 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.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.SymbolSearch { - internal interface IRemoteSymbolSearchUpdateService + internal interface IRemoteSymbolSearchUpdateEngine { - 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); + 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); } } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs index 93fffce2ead10..bfe34a21e5f1a 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchLogService.cs @@ -2,7 +2,6 @@ // 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 @@ -12,7 +11,7 @@ namespace Microsoft.CodeAnalysis.SymbolSearch /// internal interface ISymbolSearchLogService { - ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken); - ValueTask LogInfoAsync(string text, CancellationToken cancellationToken); + Task LogExceptionAsync(string exception, string text); + Task LogInfoAsync(string text); } } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs index 5f1404a7ac876..30c959949d02e 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs @@ -8,7 +8,6 @@ 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; @@ -28,7 +27,7 @@ internal interface ISymbolSearchService : IWorkspaceService /// Implementations should return results in order from best to worst (from their /// perspective). /// - ValueTask> FindPackagesWithTypeAsync( + Task> FindPackagesWithTypeAsync( string source, string name, int arity, CancellationToken cancellationToken); /// @@ -39,7 +38,7 @@ ValueTask> FindPackagesWithTypeAsync( /// Implementations should return results in order from best to worst (from their /// perspective). /// - ValueTask> FindPackagesWithAssemblyAsync( + Task> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken); /// @@ -51,18 +50,14 @@ ValueTask> FindPackagesWithAssemblyAsy /// Implementations should return results in order from best to worst (from their /// perspective). /// - ValueTask> FindReferenceAssembliesWithTypeAsync( + Task> FindReferenceAssembliesWithTypeAsync( string name, int arity, CancellationToken cancellationToken); } - [DataContract] internal abstract class PackageResult { - [DataMember(Order = 0)] public readonly string PackageName; - - [DataMember(Order = 1)] - public readonly int Rank; + internal readonly int Rank; protected PackageResult(string packageName, int rank) { @@ -71,45 +66,37 @@ protected PackageResult(string packageName, int rank) } } - [DataContract] - internal sealed class PackageWithTypeResult : PackageResult + internal class PackageWithTypeResult : PackageResult { - [DataMember(Order = 2)] + public readonly IList ContainingNamespaceNames; public readonly string TypeName; - - [DataMember(Order = 3)] public readonly string? Version; - [DataMember(Order = 4)] - public readonly ImmutableArray ContainingNamespaceNames; - public PackageWithTypeResult( string packageName, - int rank, string typeName, - string? version, - ImmutableArray containingNamespaceNames) + string version, + int rank, + IList containingNamespaceNames) : base(packageName, rank) { TypeName = typeName; - Version = version; + Version = string.IsNullOrWhiteSpace(version) ? null : version; ContainingNamespaceNames = containingNamespaceNames; } } - [DataContract] - internal sealed class PackageWithAssemblyResult : PackageResult, IEquatable, IComparable + internal class PackageWithAssemblyResult : PackageResult, IEquatable, IComparable { - [DataMember(Order = 2)] public readonly string? Version; public PackageWithAssemblyResult( string packageName, - int rank, - string version) + string version, + int rank) : base(packageName, rank) { - Version = version; + Version = string.IsNullOrWhiteSpace(version) ? null : version; } public override int GetHashCode() @@ -133,22 +120,16 @@ public int CompareTo(PackageWithAssemblyResult? other) ImmutableArray.Create>(p => p.Rank, p => p.PackageName); } - [DataContract] - internal sealed class ReferenceAssemblyWithTypeResult + internal class ReferenceAssemblyWithTypeResult { - [DataMember(Order = 0)] + public readonly IList ContainingNamespaceNames; public readonly string AssemblyName; - - [DataMember(Order = 1)] public readonly string TypeName; - [DataMember(Order = 2)] - public readonly ImmutableArray ContainingNamespaceNames; - public ReferenceAssemblyWithTypeResult( string assemblyName, string typeName, - ImmutableArray containingNamespaceNames) + IList containingNamespaceNames) { AssemblyName = assemblyName; TypeName = typeName; @@ -165,13 +146,22 @@ public DefaultSymbolSearchService() { } - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindPackagesWithTypeAsync( + string source, string name, int arity, CancellationToken cancellationToken) + { + return SpecializedTasks.EmptyList(); + } - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindPackagesWithAssemblyAsync( + string source, string assemblyName, CancellationToken cancellationToken) + { + return SpecializedTasks.EmptyList(); + } - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => new(ImmutableArray.Empty); + public Task> FindReferenceAssembliesWithTypeAsync( + string name, int arity, CancellationToken cancellationToken) + { + return SpecializedTasks.EmptyList(); + } } } diff --git a/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchUpdateEngine.cs index e7891ed6388ef..4d7bf2db34729 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 { - ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken); + Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory); - ValueTask> FindPackagesWithTypeAsync( + Task> FindPackagesWithTypeAsync( string source, string name, int arity, CancellationToken cancellationToken); - ValueTask> FindPackagesWithAssemblyAsync( + Task> FindPackagesWithAssemblyAsync( string source, string assemblyName, CancellationToken cancellationToken); - ValueTask> FindReferenceAssembliesWithTypeAsync( + Task> 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 cf26b2e2c049d..2123d1cbc6fc0 100644 --- a/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs +++ b/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs @@ -13,8 +13,8 @@ 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 IRemoteTodoCommentsDiscoveryService + internal interface IRemoteTodoCommentsService { - ValueTask ComputeTodoCommentsAsync(CancellationToken cancellation); + Task ComputeTodoCommentsAsync(CancellationToken cancellation); } } diff --git a/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsListener.cs b/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsListener.cs index 3258d8077b12f..9a4d718b5ffb2 100644 --- a/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsListener.cs +++ b/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsListener.cs @@ -15,6 +15,6 @@ namespace Microsoft.CodeAnalysis.TodoComments /// internal interface ITodoCommentsListener { - ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken); + Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs b/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs index 2676e24bba86a..afc80298a0588 100644 --- a/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs +++ b/src/Workspaces/Core/Portable/TodoComments/TodoCommentData.cs @@ -5,7 +5,6 @@ #nullable enable using System; -using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -14,48 +13,17 @@ namespace Microsoft.CodeAnalysis.TodoComments /// /// Serialization type used to pass information to/from OOP and VS. /// - [DataContract] - internal readonly struct TodoCommentData : IEquatable + internal struct TodoCommentData : IEquatable { - [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 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; public override bool Equals(object? obj) => obj is TodoCommentData other && Equals(other); @@ -64,14 +32,16 @@ public override int GetHashCode() => GetHashCode(this); public override string ToString() - => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine}, {MappedColumn}) [original: {OriginalFilePath ?? ""} ({OriginalLine}, {OriginalColumn})"; + => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine.ToString()}, {MappedColumn.ToString()}) [original: {OriginalFilePath ?? ""} ({OriginalLine.ToString()}, {OriginalColumn.ToString()})"; public bool Equals(TodoCommentData right) - => DocumentId == right.DocumentId && - Priority == right.Priority && - Message == right.Message && - OriginalLine == right.OriginalLine && - OriginalColumn == right.OriginalColumn; + { + return 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, @@ -94,14 +64,19 @@ internal void WriteTo(ObjectWriter writer) } internal static TodoCommentData ReadFrom(ObjectReader reader) - => 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()); + { + 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(), + }; + } } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs index b7a29f8c918ec..ead29c303e77d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs @@ -2,7 +2,6 @@ // 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 @@ -30,34 +29,26 @@ public DocumentKey(ProjectKey project, DocumentId id, string filePath, string na } public static explicit operator DocumentKey(Document document) - => new((ProjectKey)document.Project, document.Id, document.FilePath, document.Name); + => new DocumentKey((ProjectKey)document.Project, document.Id, document.FilePath, document.Name); public SerializableDocumentKey Dehydrate() - => new(Project.Dehydrate(), Id, FilePath, Name); + { + return new SerializableDocumentKey + { + Project = Project.Dehydrate(), + Id = Id, + FilePath = FilePath, + Name = Name, + }; + } } - [DataContract] - internal readonly struct SerializableDocumentKey + internal class SerializableDocumentKey { - [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 SerializableProjectKey Project; + public DocumentId Id; + public string FilePath; + public string 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 5d81d2ad19f65..680d1d244c257 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs @@ -2,7 +2,6 @@ // 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 @@ -30,36 +29,28 @@ public ProjectKey(SolutionKey solution, ProjectId id, string filePath, string na } public static explicit operator ProjectKey(Project project) - => new((SolutionKey)project.Solution, project.Id, project.FilePath, project.Name); + => new ProjectKey((SolutionKey)project.Solution, project.Id, project.FilePath, project.Name); public SerializableProjectKey Dehydrate() - => new(Solution.Dehydrate(), Id, FilePath, Name); + { + return new SerializableProjectKey + { + Solution = Solution.Dehydrate(), + Id = Id, + FilePath = FilePath, + Name = Name, + }; + } } - [DataContract] - internal readonly struct SerializableProjectKey + internal class SerializableProjectKey { - [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 SerializableSolutionKey Solution; + public ProjectId Id; + public string FilePath; + public string Name; public ProjectKey Rehydrate() - => new(Solution.Rehydrate(), Id, FilePath, Name); + => new ProjectKey(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 9bd8ba8b09c10..f2569e7ac0eb1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs @@ -2,7 +2,6 @@ // 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 @@ -27,32 +26,26 @@ public SolutionKey(SolutionId id, string filePath, bool isPrimaryBranch) } public static explicit operator SolutionKey(Solution solution) - => new(solution.Id, solution.FilePath, solution.BranchId == solution.Workspace.PrimaryBranchId); + => new SolutionKey(solution.Id, solution.FilePath, solution.BranchId == solution.Workspace.PrimaryBranchId); public SerializableSolutionKey Dehydrate() - => new(Id, FilePath, IsPrimaryBranch); + { + return new SerializableSolutionKey + { + Id = Id, + FilePath = FilePath, + IsPrimaryBranch = IsPrimaryBranch, + }; + } } - [DataContract] - internal readonly struct SerializableSolutionKey + internal class SerializableSolutionKey { - [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 SolutionId Id; + public string FilePath; + public bool IsPrimaryBranch; public SolutionKey Rehydrate() - => new(Id, FilePath, IsPrimaryBranch); + => new SolutionKey(Id, FilePath, IsPrimaryBranch); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs index 0f5d07ac7aa2f..b81b7662ee16d 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Linq; using System.Runtime.InteropServices; -using System.Runtime.Serialization; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis @@ -16,7 +15,6 @@ 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 { /// @@ -26,12 +24,8 @@ 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 @@ -101,6 +95,9 @@ private static unsafe Checksum FromWorker(byte[] checksum) } } + private Checksum(HashData hash) + => _checksum = hash; + public bool Equals(Checksum other) { if (other == null) @@ -152,25 +149,17 @@ 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)] - public readonly struct HashData : IEquatable + private struct HashData : IEquatable { - [FieldOffset(0), DataMember(Order = 0)] - private readonly long Data1; + [FieldOffset(0)] + private long Data1; - [FieldOffset(8), DataMember(Order = 1)] - private readonly long Data2; + [FieldOffset(8)] + private long Data2; - [FieldOffset(16), DataMember(Order = 2)] - private readonly int Data3; - - public HashData(long data1, long data2, int data3) - { - Data1 = data1; - Data2 = data2; - Data3 = data3; - } + [FieldOffset(16)] + private int Data3; public static bool operator ==(HashData x, HashData y) => x.Equals(y); @@ -186,10 +175,22 @@ public void WriteTo(ObjectWriter writer) } public static unsafe HashData FromPointer(HashData* hash) - => new(hash->Data1, hash->Data2, hash->Data3); + { + HashData result = default; + result.Data1 = hash->Data1; + result.Data2 = hash->Data2; + result.Data3 = hash->Data3; + return result; + } public static HashData ReadFrom(ObjectReader reader) - => new(reader.ReadInt64(), reader.ReadInt64(), reader.ReadInt32()); + { + HashData result = default; + result.Data1 = reader.ReadInt64(); + result.Data2 = reader.ReadInt64(); + result.Data3 = reader.ReadInt32(); + return result; + } public override int GetHashCode() { diff --git a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs b/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs deleted file mode 100644 index cd535d37c0350..0000000000000 --- a/src/Workspaces/CoreTest/Remote/ServiceDescriptorTests.cs +++ /dev/null @@ -1,166 +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.IO; -using System.IO.Pipelines; -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)) - { - // types that are special cased by JSON-RPC for streaming APIs - if (type != typeof(Stream) && - type != typeof(IDuplexPipe) && - type != typeof(PipeReader) && - type != typeof(PipeWriter)) - { - 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/Remote/InProcRemostHostClient.cs b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs index 9b1d77c30520c..eae3747ec9a67 100644 --- a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs +++ b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.IO.Pipelines; using System.Runtime.Remoting; using System.Text; using System.Threading; @@ -37,7 +36,7 @@ internal sealed partial class InProcRemoteHostClient : RemoteHostClient, IRemote public static async Task CreateAsync(HostWorkspaceServices services, TraceListener? traceListener, RemoteHostTestData testData) { - var inprocServices = new InProcRemoteServices(services, traceListener, testData); + var inprocServices = new InProcRemoteServices(traceListener, testData); var remoteHostStream = await inprocServices.RequestServiceAsync(WellKnownServiceHubService.RemoteHost).ConfigureAwait(false); @@ -105,29 +104,6 @@ public Task IsExperimentEnabledAsync(string experimentName, CancellationTo public void RegisterService(RemoteServiceName serviceName, Func serviceCreator) => _inprocServices.RegisterService(serviceName, serviceCreator); - public override async ValueTask> CreateConnectionAsync(object? callbackTarget, CancellationToken cancellationToken) - { - var options = new ServiceActivationOptions(); - - if (callbackTarget is not null) - { - options.ClientRpcTarget = callbackTarget; - } - - var assetStorage = _workspaceServices.GetRequiredService().AssetStorage; - var descriptor = ServiceDescriptors.GetServiceDescriptor(typeof(T), isRemoteHost64Bit: IntPtr.Size == 8); - - // Make sure we are on the thread pool to avoid UI thread dependencies if external code uses ConfigureAwait(true) - await TaskScheduler.Default; - -#pragma warning disable ISB001 // Dispose of proxies - caller disposes - var proxy = await _inprocServices.ServiceBroker.GetProxyAsync(descriptor, options, cancellationToken).ConfigureAwait(false); -#pragma warning restore - - Contract.ThrowIfNull(proxy); - return new BrokeredServiceConnection(proxy, assetStorage, _workspaceServices.GetRequiredService(), shutdownCancellationService: null); - } - public override async Task CreateConnectionAsync(RemoteServiceName serviceName, object? callbackTarget, CancellationToken cancellationToken) { // get stream from service hub to communicate service specific information @@ -176,63 +152,13 @@ public object GetService(Type serviceType) } } - private sealed class InProcServiceBroker : IServiceBroker - { - private readonly InProcRemoteServices _services; - - public InProcServiceBroker(InProcRemoteServices services) - { - _services = services; - } - - public event EventHandler? AvailabilityChanged { add { } remove { } } - - // This method is currently not needed for our IServiceBroker usage patterns. - public ValueTask GetPipeAsync(ServiceMoniker serviceMoniker, ServiceActivationOptions options, CancellationToken cancellationToken) - => throw ExceptionUtilities.Unreachable; - - public ValueTask GetProxyAsync(ServiceRpcDescriptor descriptor, ServiceActivationOptions options, CancellationToken cancellationToken) where T : class - { - var pipePair = FullDuplexStream.CreatePipePair(); - - var clientConnection = descriptor - .WithTraceSource(_services.ServiceProvider.TraceSource) - .ConstructRpcConnection(pipePair.Item2); - - Contract.ThrowIfFalse(options.ClientRpcTarget is null == descriptor.ClientInterface is null); - - if (descriptor.ClientInterface != null) - { - Contract.ThrowIfNull(options.ClientRpcTarget); - clientConnection.AddLocalRpcTarget(options.ClientRpcTarget); - } - - // Clear RPC target so that the server connection is forced to create a new proxy for the callback - // instead of just invoking the callback object directly (this emulates the product that does - // not serialize the callback object over). - options.ClientRpcTarget = null; - - // Creates service instance and connects it to the pipe. - // We don't need to store the instance anywhere. - _ = _services.CreateBrokeredService(descriptor, pipePair.Item1, options); - - clientConnection.StartListening(); - - return new ValueTask(clientConnection.ConstructRpcClient()); - } - } - private sealed class InProcRemoteServices { public readonly ServiceProvider ServiceProvider; - private readonly Dictionary> _inProcBrokeredServicesMap = new(); - private readonly Dictionary _remoteBrokeredServicesMap = new(); private readonly Dictionary> _factoryMap = new(); private readonly Dictionary _serviceNameMap = new(); - public readonly IServiceBroker ServiceBroker; - - public InProcRemoteServices(HostWorkspaceServices workspaceServices, TraceListener? traceListener, RemoteHostTestData testData) + public InProcRemoteServices(TraceListener? traceListener, RemoteHostTestData testData) { var remoteLogger = new TraceSource("InProcRemoteClient") { @@ -246,29 +172,12 @@ public InProcRemoteServices(HostWorkspaceServices workspaceServices, TraceListen ServiceProvider = new ServiceProvider(remoteLogger, testData); - ServiceBroker = new InProcServiceBroker(this); - RegisterService(WellKnownServiceHubService.RemoteHost, (s, p, o) => new RemoteHostService(s, p)); - RegisterInProcBrokeredService(SolutionAssetProvider.ServiceDescriptor, () => new SolutionAssetProvider(workspaceServices)); - RegisterRemoteBrokeredService(new RemoteSymbolSearchUpdateService.Factory()); - RegisterRemoteBrokeredService(new RemoteDesignerAttributeDiscoveryService.Factory()); - RegisterRemoteBrokeredService(new RemoteProjectTelemetryService.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.CodeAnalysis, (s, p, o) => new CodeAnalysisService(s, p)); + RegisterService(WellKnownServiceHubService.RemoteSymbolSearchUpdateEngine, (s, p, o) => new RemoteSymbolSearchUpdateEngine(s, p)); + RegisterService(WellKnownServiceHubService.RemoteDesignerAttributeService, (s, p, o) => new RemoteDesignerAttributeService(s, p)); + RegisterService(WellKnownServiceHubService.RemoteProjectTelemetryService, (s, p, o) => new RemoteProjectTelemetryService(s, p)); + RegisterService(WellKnownServiceHubService.RemoteTodoCommentsService, (s, p, o) => new RemoteTodoCommentsService(s, p)); RegisterService(WellKnownServiceHubService.LanguageServer, (s, p, o) => new LanguageServer(s, p)); } @@ -287,42 +196,6 @@ public Task RequestServiceAsync(RemoteServiceName serviceName) return Task.FromResult(new WrappedStream(factory(streams.Item1, ServiceProvider, default), streams.Item2)); } - public void RegisterInProcBrokeredService(ServiceDescriptor serviceDescriptor, Func serviceFactory) - { - _inProcBrokeredServicesMap.Add(serviceDescriptor.Moniker, serviceFactory); - } - - public void RegisterRemoteBrokeredService(BrokeredServiceBase.IFactory serviceFactory) - { - var moniker = ServiceDescriptors.GetServiceDescriptor(serviceFactory.ServiceType, isRemoteHost64Bit: IntPtr.Size == 8).Moniker; - _remoteBrokeredServicesMap.Add(moniker, serviceFactory); - } - - public object CreateBrokeredService(ServiceRpcDescriptor descriptor, IDuplexPipe pipe, ServiceActivationOptions options) - { - if (_inProcBrokeredServicesMap.TryGetValue(descriptor.Moniker, out var inProcFactory)) - { - // This code is similar to service creation implemented in BrokeredServiceBase.FactoryBase. - // 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.WithTraceSource(ServiceProvider.TraceSource).ConstructRpcConnection(pipe); - var service = inProcFactory(); - - serviceConnection.AddLocalRpcTarget(service); - serviceConnection.StartListening(); - - return service; - } - - if (_remoteBrokeredServicesMap.TryGetValue(descriptor.Moniker, out var remoteFactory)) - { - return remoteFactory.Create(pipe, ServiceProvider, options, ServiceBroker); - } - - throw ExceptionUtilities.UnexpectedValue(descriptor.Moniker); - } - private sealed class WrappedStream : Stream { private readonly IDisposable _service; diff --git a/src/Workspaces/CoreTestUtilities/Roslyn.Services.UnitTests.Utilities.csproj b/src/Workspaces/CoreTestUtilities/Roslyn.Services.UnitTests.Utilities.csproj index 96db67ac6f827..62a0430360caa 100644 --- a/src/Workspaces/CoreTestUtilities/Roslyn.Services.UnitTests.Utilities.csproj +++ b/src/Workspaces/CoreTestUtilities/Roslyn.Services.UnitTests.Utilities.csproj @@ -4,7 +4,7 @@ Library Microsoft.CodeAnalysis.UnitTests - net5.0;netcoreapp3.1;net472 + net5.0-windows;netcoreapp3.1;net472 true false true diff --git a/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs b/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs deleted file mode 100644 index 936cca6ecea2a..0000000000000 --- a/src/Workspaces/Remote/Core/BrokeredServiceConnection.cs +++ /dev/null @@ -1,280 +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.IO; -using System.IO.Pipelines; -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 Roslyn.Utilities; -using StreamJsonRpc; -using StreamJsonRpc.Protocol; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class BrokeredServiceConnection : RemoteServiceConnection - where TService : class - { - private readonly IErrorReportingService? _errorReportingService; - private readonly IRemoteHostClientShutdownCancellationService? _shutdownCancellationService; - private readonly SolutionAssetStorage _solutionAssetStorage; - private readonly TService _service; - - public BrokeredServiceConnection( - TService service, - SolutionAssetStorage solutionAssetStorage, - IErrorReportingService? errorReportingService, - IRemoteHostClientShutdownCancellationService? shutdownCancellationService) - { - _errorReportingService = errorReportingService; - _shutdownCancellationService = shutdownCancellationService; - _solutionAssetStorage = solutionAssetStorage; - _service = service; - } - - public override void Dispose() - => (_service as IDisposable)?.Dispose(); - - // without solution - - public override async ValueTask TryInvokeAsync(Func invocation, CancellationToken cancellationToken) - { - try - { - await invocation(_service, cancellationToken).ConfigureAwait(false); - return true; - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return false; - } - } - - public override async ValueTask> TryInvokeAsync(Func> invocation, CancellationToken cancellationToken) - { - try - { - return await invocation(_service, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return default; - } - } - - public override async ValueTask> TryInvokeAsync( - Func invocation, - Func> reader, - CancellationToken cancellationToken) - { - try - { - return await InvokeStreamingServiceAsync(_service, invocation, reader, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return default; - } - } - - // with solution - - public override async ValueTask TryInvokeAsync(Solution solution, Func invocation, CancellationToken cancellationToken) - { - try - { - using var scope = await _solutionAssetStorage.StoreAssetsAsync(solution, cancellationToken).ConfigureAwait(false); - await invocation(_service, scope.SolutionInfo, cancellationToken).ConfigureAwait(false); - return true; - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return false; - } - } - - public override async ValueTask> TryInvokeAsync(Solution solution, Func> invocation, CancellationToken cancellationToken) - { - try - { - using var scope = await _solutionAssetStorage.StoreAssetsAsync(solution, cancellationToken).ConfigureAwait(false); - return await invocation(_service, scope.SolutionInfo, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return default; - } - } - - public override async ValueTask> TryInvokeAsync( - Solution solution, - Func invocation, - Func> reader, - CancellationToken cancellationToken) - { - try - { - using var scope = await _solutionAssetStorage.StoreAssetsAsync(solution, cancellationToken).ConfigureAwait(false); - return await InvokeStreamingServiceAsync( - _service, - (service, pipeWriter, cancellationToken) => invocation(service, scope.SolutionInfo, pipeWriter, cancellationToken), - reader, - cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - OnUnexpectedException(exception, cancellationToken); - return default; - } - } - - internal static async ValueTask InvokeStreamingServiceAsync( - TService service, - Func invocation, - Func> reader, - CancellationToken cancellationToken) - { - // We can cancel at entry, but once the pipe operations are scheduled we rely on both operations running to - // avoid deadlocks (the exception handler in 'writerTask' ensures progress is made in 'readerTask'). - cancellationToken.ThrowIfCancellationRequested(); - var mustNotCancelToken = CancellationToken.None; - - var pipe = new Pipe(); - - // Create new tasks that both start executing, rather than invoking the delegates directly - // to make sure both invocation and reader start executing and transfering data. - - var writerTask = Task.Run(async () => - { - try - { - await invocation(service, pipe.Writer, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) - { - // Ensure that the writer is complete if an exception is thrown - // before the writer is passed to the RPC proxy. Once it's passed to the proxy - // the proxy should complete it as soon as the remote side completes it. - await pipe.Writer.CompleteAsync(e).ConfigureAwait(false); - - throw; - } - }, mustNotCancelToken); - - var readerTask = Task.Run( - async () => - { - Exception? exception = null; - - try - { - return await reader(pipe.Reader, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) when ((exception = e) == null) - { - throw ExceptionUtilities.Unreachable; - } - finally - { - await pipe.Reader.CompleteAsync(exception).ConfigureAwait(false); - } - }, mustNotCancelToken); - - await Task.WhenAll(writerTask, readerTask).ConfigureAwait(false); - - return readerTask.Result; - } - - private bool ReportUnexpectedException(Exception exception, CancellationToken cancellationToken) - { - if (exception is OperationCanceledException) - { - // It's a bug for a service to throw OCE based on a different cancellation token than it has received in the call. - // The server side filter will report NFW in such scenario, so that the underlying issue can be fixed. - // Do not treat this as a critical failure of the service for now and only fail in debug build. - Debug.Assert(cancellationToken.IsCancellationRequested); - - return false; - } - - // 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.ReportWithoutCrash(exception); - } - - 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) - { - // 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(); - - 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.ShowFeatureNotAvailableErrorInfo(message, internalException); - } - } -} diff --git a/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs b/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs index b31e6fe36cce4..a12b667038805 100644 --- a/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs +++ b/src/Workspaces/Remote/Core/GlobalNotificationRemoteDeliveryService.cs @@ -94,8 +94,11 @@ private async Task SendStartNotificationAsync(Task( - (service, cancellationToken) => service.OnGlobalOperationStartedAsync(cancellationToken), + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteGlobalNotificationDeliveryService.OnGlobalOperationStarted), + solution: null, + Array.Empty(), callbackTarget: null, _cancellationToken).ConfigureAwait(false); @@ -126,8 +129,11 @@ private async Task SendStoppedNotificationAsync(Task( - (service, cancellationToken) => service.OnGlobalOperationStoppedAsync(e.Operations, e.Cancelled, cancellationToken), + await client.RunRemoteAsync( + WellKnownServiceHubService.CodeAnalysis, + nameof(IRemoteGlobalNotificationDeliveryService.OnGlobalOperationStopped), + solution: null, + new object[] { e.Operations, e.Cancelled }, callbackTarget: null, _cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs b/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs index 9fd47a3e1c8e4..33932ee12bb12 100644 --- a/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs +++ b/src/Workspaces/Remote/Core/IRemoteGlobalNotificationDeliveryService.cs @@ -5,15 +5,13 @@ #nullable enable using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Remote { internal interface IRemoteGlobalNotificationDeliveryService { - ValueTask OnGlobalOperationStartedAsync(CancellationToken cancellationToken); + void OnGlobalOperationStarted(); - ValueTask OnGlobalOperationStoppedAsync(IReadOnlyList operations, bool cancelled, CancellationToken cancellationToken); + void OnGlobalOperationStopped(IReadOnlyList operations, bool cancelled); } } diff --git a/src/Workspaces/Remote/Core/IRemoteHostService.cs b/src/Workspaces/Remote/Core/IRemoteHostService.cs index f05329a4ef310..413436f9a25fa 100644 --- a/src/Workspaces/Remote/Core/IRemoteHostService.cs +++ b/src/Workspaces/Remote/Core/IRemoteHostService.cs @@ -15,7 +15,7 @@ internal interface IRemoteHostService { void InitializeGlobalState(int uiCultureLCID, int cultureLCID, CancellationToken cancellationToken); - void InitializeTelemetrySession(int hostProcessId, string serializedSession, CancellationToken cancellationToken); + void InitializeTelemetrySession(string host, string serializedSession, CancellationToken cancellationToken); /// /// This is only for debugging diff --git a/src/Workspaces/Remote/Core/ISolutionAssetProvider.cs b/src/Workspaces/Remote/Core/ISolutionAssetProvider.cs deleted file mode 100644 index 50cc9f111a18c..0000000000000 --- a/src/Workspaces/Remote/Core/ISolutionAssetProvider.cs +++ /dev/null @@ -1,28 +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.IO; -using System.IO.Pipelines; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Brokered service. - /// - internal interface ISolutionAssetProvider - { - /// - /// Streams serialized assets into the given stream. - /// - ValueTask GetAssetsAsync(PipeWriter pipeWriter, int scopeId, Checksum[] checksums, CancellationToken cancellationToken); - - // TODO: remove (https://github.com/dotnet/roslyn/issues/43477) - ValueTask IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken); - } -} diff --git a/src/Workspaces/Remote/Core/RemoteCallback.cs b/src/Workspaces/Remote/Core/RemoteCallback.cs deleted file mode 100644 index 089d312b3fdd5..0000000000000 --- a/src/Workspaces/Remote/Core/RemoteCallback.cs +++ /dev/null @@ -1,132 +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.IO; -using System.IO.Pipelines; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; -using Roslyn.Utilities; -using StreamJsonRpc; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Wraps calls from a remote brokered service back to the client or to an in-proc brokered service. - /// The purpose of this type is to handle exceptions thrown by the underlying remoting infrastructure - /// in manner that's compatible with our exception handling policies. - /// - /// TODO: This wrapper might not be needed once https://github.com/microsoft/vs-streamjsonrpc/issues/246 is fixed. - /// - internal readonly struct RemoteCallback - where T : class - { - private readonly T _callback; - - public RemoteCallback(T callback) - { - _callback = callback; - } - - public async ValueTask InvokeAsync(Func invocation, CancellationToken cancellationToken) - { - try - { - await invocation(_callback, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - throw OnUnexpectedException(exception, cancellationToken); - } - } - - public async ValueTask InvokeAsync(Func> invocation, CancellationToken cancellationToken) - { - try - { - return await invocation(_callback, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - throw OnUnexpectedException(exception, cancellationToken); - } - } - - /// - /// Invokes a remote API that streams results back to the caller. - /// - public async ValueTask InvokeAsync( - Func invocation, - Func> reader, - CancellationToken cancellationToken) - { - try - { - return await BrokeredServiceConnection.InvokeStreamingServiceAsync(_callback, invocation, reader, cancellationToken).ConfigureAwait(false); - } - catch (Exception exception) when (ReportUnexpectedException(exception, cancellationToken)) - { - throw OnUnexpectedException(exception, cancellationToken); - } - } - - // 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 - // - private static bool ReportUnexpectedException(Exception exception, CancellationToken cancellationToken) - { - if (exception is IOException) - { - // propagate intermittent exceptions without reporting telemetry: - return false; - } - - if (exception is OperationCanceledException) - { - if (cancellationToken.IsCancellationRequested) - { - // Cancellation was requested and expected - return false; - } - - return true; - } - - // 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) - { - return true; - } - - // Indicates bug on client side or in serialization, report NFW and propagate the exception. - return FatalError.ReportWithoutCrashAndPropagate(exception); - } - - private static Exception OnUnexpectedException(Exception exception, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (exception is ConnectionLostException) - { - throw new OperationCanceledException(exception.Message, exception); - } - - // If this is hit the cancellation token passed to the service implementation did not use the correct token, - // and the resulting exception was not a ConnectionLostException. - return ExceptionUtilities.Unreachable; - } - } -} diff --git a/src/Workspaces/Remote/Core/RemoteEndPoint.cs b/src/Workspaces/Remote/Core/RemoteEndPoint.cs index 86ab1ec0f0d13..9f10fb2ec6825 100644 --- a/src/Workspaces/Remote/Core/RemoteEndPoint.cs +++ b/src/Workspaces/Remote/Core/RemoteEndPoint.cs @@ -58,6 +58,9 @@ public RemoteEndPoint(Stream stream, TraceSource logger, object? incomingCallTar var jsonFormatter = new JsonMessageFormatter(); + // disable interpreting of strings as DateTime during deserialization: + jsonFormatter.JsonSerializer.DateParseHandling = DateParseHandling.None; + if (jsonConverters != null) { jsonFormatter.JsonSerializer.Converters.AddRange(jsonConverters); diff --git a/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs b/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs index 98687ae610335..c1cc98eb766d7 100644 --- a/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs +++ b/src/Workspaces/Remote/Core/RemoteHostAssetSerialization.cs @@ -12,42 +12,12 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; -using System; -using System.IO.Pipelines; -using Microsoft.VisualStudio.Threading; -using System.Diagnostics; namespace Microsoft.CodeAnalysis.Remote { internal static class RemoteHostAssetSerialization { - internal static readonly PipeOptions PipeOptionsWithUnlimitedWriterBuffer = new(pauseWriterThreshold: long.MaxValue); - public static async Task WriteDataAsync(ObjectWriter writer, SolutionAssetStorage assetStorage, ISerializerService serializer, int scopeId, Checksum[] checksums, CancellationToken cancellationToken) - { - SolutionAsset? singleAsset = null; - IReadOnlyDictionary? assetMap = null; - - if (checksums.Length == 1) - { - singleAsset = (await assetStorage.GetAssetAsync(scopeId, checksums[0], cancellationToken).ConfigureAwait(false)) ?? SolutionAsset.Null; - } - else - { - assetMap = await assetStorage.GetAssetsAsync(scopeId, checksums, cancellationToken).ConfigureAwait(false); - } - - WriteData(writer, singleAsset, assetMap, serializer, scopeId, checksums, cancellationToken); - } - - public static void WriteData( - ObjectWriter writer, - SolutionAsset? singleAsset, - IReadOnlyDictionary? assetMap, - ISerializerService serializer, - int scopeId, - Checksum[] checksums, - CancellationToken cancellationToken) { writer.WriteInt32(scopeId); @@ -58,17 +28,21 @@ public static void WriteData( return; } - if (singleAsset != null) + if (checksums.Length == 1) { + var checksum = checksums[0]; + + var asset = (await assetStorage.GetAssetAsync(scopeId, checksum, cancellationToken).ConfigureAwait(false)) ?? SolutionAsset.Null; writer.WriteInt32(1); - WriteAsset(writer, serializer, checksums[0], singleAsset, cancellationToken); + + WriteAsset(writer, serializer, checksum, asset, cancellationToken); return; } - Debug.Assert(assetMap != null); - writer.WriteInt32(assetMap.Count); + var assets = await assetStorage.GetAssetsAsync(scopeId, checksums, cancellationToken).ConfigureAwait(false); + writer.WriteInt32(assets.Count); - foreach (var (checksum, asset) in assetMap) + foreach (var (checksum, asset) in assets) { WriteAsset(writer, serializer, checksum, asset, cancellationToken); } @@ -86,60 +60,6 @@ static void WriteAsset(ObjectWriter writer, ISerializerService serializer, Check } } - public static async ValueTask> ReadDataAsync(PipeReader pipeReader, int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) - { - // We can cancel at entry, but once the pipe operations are scheduled we rely on both operations running to - // avoid deadlocks (the exception handler in 'copyTask' ensures progress is made in the blocking read). - cancellationToken.ThrowIfCancellationRequested(); - var mustNotCancelToken = CancellationToken.None; - - // Workaround for ObjectReader not supporting async reading. - // Unless we read from the RPC stream asynchronously and with cancallation support we might hang when the server cancels. - // https://github.com/dotnet/roslyn/issues/47861 - - // Use local pipe to avoid blocking the current thread on networking IO. - var localPipe = new Pipe(PipeOptionsWithUnlimitedWriterBuffer); - - Exception? exception = null; - - // start a task on a thread pool thread copying from the RPC pipe to a local pipe: - var copyTask = Task.Run(async () => - { - try - { - await pipeReader.CopyToAsync(localPipe.Writer, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) - { - exception = e; - } - finally - { - await localPipe.Writer.CompleteAsync(exception).ConfigureAwait(false); - await pipeReader.CompleteAsync(exception).ConfigureAwait(false); - } - }, mustNotCancelToken); - - // blocking read from the local pipe on the current thread: - try - { - using var stream = localPipe.Reader.AsStream(leaveOpen: false); - return ReadData(stream, scopeId, checksums, serializerService, cancellationToken); - } - catch (EndOfStreamException) - { - cancellationToken.ThrowIfCancellationRequested(); - - throw exception ?? ExceptionUtilities.Unreachable; - } - finally - { - // Make sure to complete the copy and pipes before returning, otherwise the caller could complete the - // reader and/or writer while they are still in use. - await copyTask.ConfigureAwait(false); - } - } - public static ImmutableArray<(Checksum, object)> ReadData(Stream stream, int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) { using var _ = ArrayBuilder<(Checksum, object)>.GetInstance(out var results); diff --git a/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs b/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs deleted file mode 100644 index 7389dc20c37e6..0000000000000 --- a/src/Workspaces/Remote/Core/Serialization/ImmutableCollectionMessagePackResolver.cs +++ /dev/null @@ -1,394 +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.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(options.Security.GetEqualityComparer()); - } - - protected override ImmutableHashSet.Enumerator GetSourceEnumerator(ImmutableHashSet source) - { - return source.GetEnumerator(); - } - } - - internal sealed class ImmutableSortedDictionaryFormatter : DictionaryFormatterBase.Builder, ImmutableSortedDictionary.Enumerator, ImmutableSortedDictionary> - { - protected override void Add(ImmutableSortedDictionary.Builder collection, int index, TKey key, TValue value, MessagePackSerializerOptions options) - { - collection.Add(key, value); - } - - protected override ImmutableSortedDictionary Complete(ImmutableSortedDictionary.Builder intermediateCollection) - { - return intermediateCollection.ToImmutable(); - } - - protected override ImmutableSortedDictionary.Builder Create(int count, MessagePackSerializerOptions options) - { - return ImmutableSortedDictionary.CreateBuilder(); - } - - protected override ImmutableSortedDictionary.Enumerator GetSourceEnumerator(ImmutableSortedDictionary source) - { - return source.GetEnumerator(); - } - } - - internal sealed class ImmutableSortedSetFormatter : CollectionFormatterBase.Builder, ImmutableSortedSet.Enumerator, ImmutableSortedSet> - { - protected override void Add(ImmutableSortedSet.Builder collection, int index, T value, MessagePackSerializerOptions options) - { - collection.Add(value); - } - - protected override ImmutableSortedSet Complete(ImmutableSortedSet.Builder intermediateCollection) - { - return intermediateCollection.ToImmutable(); - } - - protected override ImmutableSortedSet.Builder Create(int count, MessagePackSerializerOptions options) - { - return ImmutableSortedSet.CreateBuilder(); - } - - protected override ImmutableSortedSet.Enumerator GetSourceEnumerator(ImmutableSortedSet source) - { - return source.GetEnumerator(); - } - } - - // not best for performance(does not use ImmutableQueue.Enumerator) - internal sealed class ImmutableQueueFormatter : CollectionFormatterBase, ImmutableQueue> - { - protected override void Add(ImmutableQueueBuilder collection, int index, T value, MessagePackSerializerOptions options) - { - collection.Add(value); - } - - protected override ImmutableQueue Complete(ImmutableQueueBuilder intermediateCollection) - { - return intermediateCollection.Q; - } - - protected override ImmutableQueueBuilder Create(int count, MessagePackSerializerOptions options) - { - return new ImmutableQueueBuilder(); - } - } - - // not best for performance(does not use ImmutableQueue.Enumerator) - internal sealed class ImmutableStackFormatter : CollectionFormatterBase> - { - protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) - { - collection[collection.Length - 1 - index] = value; - } - - protected override ImmutableStack Complete(T[] intermediateCollection) - { - return ImmutableStack.CreateRange(intermediateCollection); - } - - protected override T[] Create(int count, MessagePackSerializerOptions options) - { - return new T[count]; - } - } - - internal sealed class InterfaceImmutableListFormatter : CollectionFormatterBase.Builder, IImmutableList> - { - protected override void Add(ImmutableList.Builder collection, int index, T value, MessagePackSerializerOptions options) - { - collection.Add(value); - } - - protected override IImmutableList Complete(ImmutableList.Builder intermediateCollection) - { - return intermediateCollection.ToImmutable(); - } - - protected override ImmutableList.Builder Create(int count, MessagePackSerializerOptions options) - { - return ImmutableList.CreateBuilder(); - } - } - - internal sealed class InterfaceImmutableDictionaryFormatter : DictionaryFormatterBase.Builder, IImmutableDictionary> - { - protected override void Add(ImmutableDictionary.Builder collection, int index, TKey key, TValue value, MessagePackSerializerOptions options) - { - collection.Add(key, value); - } - - protected override IImmutableDictionary Complete(ImmutableDictionary.Builder intermediateCollection) - { - return intermediateCollection.ToImmutable(); - } - - protected override ImmutableDictionary.Builder Create(int count, MessagePackSerializerOptions options) - { - return ImmutableDictionary.CreateBuilder(options.Security.GetEqualityComparer()); - } - } - - internal sealed class InterfaceImmutableSetFormatter : CollectionFormatterBase.Builder, IImmutableSet> - { - protected override void Add(ImmutableHashSet.Builder collection, int index, T value, MessagePackSerializerOptions options) - { - collection.Add(value); - } - - protected override IImmutableSet Complete(ImmutableHashSet.Builder intermediateCollection) - { - return intermediateCollection.ToImmutable(); - } - - protected override ImmutableHashSet.Builder Create(int count, MessagePackSerializerOptions options) - { - return ImmutableHashSet.CreateBuilder(options.Security.GetEqualityComparer()); - } - } - - internal sealed class InterfaceImmutableQueueFormatter : CollectionFormatterBase, IImmutableQueue> - { - protected override void Add(ImmutableQueueBuilder collection, int index, T value, MessagePackSerializerOptions options) - { - collection.Add(value); - } - - protected override IImmutableQueue Complete(ImmutableQueueBuilder intermediateCollection) - { - return intermediateCollection.Q; - } - - protected override ImmutableQueueBuilder Create(int count, MessagePackSerializerOptions options) - { - return new ImmutableQueueBuilder(); - } - } - - internal sealed class InterfaceImmutableStackFormatter : CollectionFormatterBase> - { - protected override void Add(T[] collection, int index, T value, MessagePackSerializerOptions options) - { - collection[collection.Length - 1 - index] = value; - } - - protected override IImmutableStack Complete(T[] intermediateCollection) - { - return ImmutableStack.CreateRange(intermediateCollection); - } - - protected override T[] Create(int count, MessagePackSerializerOptions options) - { - return new T[count]; - } - } - - // pseudo builders - internal sealed class ImmutableQueueBuilder - { - public ImmutableQueue Q { get; set; } = ImmutableQueue.Empty; - - public void Add(T value) - { - Q = Q.Enqueue(value); - } - } - } -} diff --git a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs b/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs deleted file mode 100644 index fe506f3064669..0000000000000 --- a/src/Workspaces/Remote/Core/Serialization/MessagePackFormatters.cs +++ /dev/null @@ -1,307 +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.Collections.Immutable; -using System.Diagnostics; -using System.Runtime.Serialization; -using MessagePack; -using MessagePack.Formatters; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.ConvertTupleToStruct; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.DocumentHighlighting; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.NavigateTo; -using Microsoft.CodeAnalysis.Rename.ConflictEngine; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Defines MessagePack formatters for public types without a public constructor suitable for deserialization. - /// Roslyn internal types should always be annotated with and have the right constructor. - /// - internal sealed class MessagePackFormatters - { - public static ImmutableArray GetFormatters() => ImmutableArray.Create( - SolutionIdFormatter.Instance, - ProjectIdFormatter.Instance, - DocumentIdFormatter.Instance, - EnumFormatters.AnalysisKind, - EnumFormatters.AnalysisKind.CreateNullable(), - EnumFormatters.HighlightSpanKind, - EnumFormatters.Scope, - EnumFormatters.RelatedLocationType, - EnumFormatters.SearchKind, - EnumFormatters.NavigateToMatchKind, - EnumFormatters.Glyph, - EnumFormatters.Glyph.CreateNullable(), - EnumFormatters.TaggedTextStyle, - EnumFormatters.ValueUsageInfo, - EnumFormatters.ValueUsageInfo.CreateNullable(), - EnumFormatters.TypeOrNamespaceUsageInfo, - EnumFormatters.TypeOrNamespaceUsageInfo.CreateNullable(), - EnumFormatters.AddImportFixKind, - EnumFormatters.CodeActionPriority, - EnumFormatters.DependentTypesKind); - - // TODO: remove https://github.com/neuecc/MessagePack-CSharp/issues/1025 - internal static class EnumFormatters - { - public static readonly EnumFormatter AnalysisKind = new(value => (int)value, value => (AnalysisKind)value); - public static readonly EnumFormatter HighlightSpanKind = new(value => (int)value, value => (HighlightSpanKind)value); - public static readonly EnumFormatter Scope = new(value => (int)value, value => (Scope)value); - public static readonly EnumFormatter RelatedLocationType = new(value => (int)value, value => (RelatedLocationType)value); - public static readonly EnumFormatter SearchKind = new(value => (int)value, value => (SearchKind)value); - public static readonly EnumFormatter NavigateToMatchKind = new(value => (int)value, value => (NavigateToMatchKind)value); - public static readonly EnumFormatter Glyph = new(value => (int)value, value => (Glyph)value); - public static readonly EnumFormatter TaggedTextStyle = new(value => (int)value, value => (TaggedTextStyle)value); - public static readonly EnumFormatter ValueUsageInfo = new(value => (int)value, value => (ValueUsageInfo)value); - public static readonly EnumFormatter TypeOrNamespaceUsageInfo = new(value => (int)value, value => (TypeOrNamespaceUsageInfo)value); - public static readonly EnumFormatter AddImportFixKind = new(value => (int)value, value => (AddImportFixKind)value); - public static readonly EnumFormatter CodeActionPriority = new(value => (int)value, value => (CodeActionPriority)value); - public static readonly EnumFormatter DependentTypesKind = new(value => (int)value, value => (DependentTypesKind)value); - } - - internal sealed class SolutionIdFormatter : IMessagePackFormatter - { - public static readonly SolutionIdFormatter Instance = new SolutionIdFormatter(); - - public SolutionId? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - try - { - if (reader.TryReadNil()) - { - return null; - } - - Contract.ThrowIfFalse(reader.ReadArrayHeader() == 2); - var id = GuidFormatter.Instance.Deserialize(ref reader, options); - var debugName = reader.ReadString(); - - return SolutionId.CreateFromSerialized(id, debugName); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public void Serialize(ref MessagePackWriter writer, SolutionId? value, MessagePackSerializerOptions options) - { - try - { - if (value is null) - { - writer.WriteNil(); - } - else - { - writer.WriteArrayHeader(2); - GuidFormatter.Instance.Serialize(ref writer, value.Id, options); - writer.Write(value.DebugName); - } - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - } - - internal sealed class ProjectIdFormatter : IMessagePackFormatter - { - public static readonly ProjectIdFormatter Instance = new ProjectIdFormatter(); - - public ProjectId? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - try - { - if (reader.TryReadNil()) - { - return null; - } - - Contract.ThrowIfFalse(reader.ReadArrayHeader() == 2); - var id = GuidFormatter.Instance.Deserialize(ref reader, options); - var debugName = reader.ReadString(); - - return ProjectId.CreateFromSerialized(id, debugName); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public void Serialize(ref MessagePackWriter writer, ProjectId? value, MessagePackSerializerOptions options) - { - try - { - if (value is null) - { - writer.WriteNil(); - } - else - { - writer.WriteArrayHeader(2); - GuidFormatter.Instance.Serialize(ref writer, value.Id, options); - writer.Write(value.DebugName); - } - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - } - - internal sealed class DocumentIdFormatter : IMessagePackFormatter - { - public static readonly DocumentIdFormatter Instance = new DocumentIdFormatter(); - - public DocumentId? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - try - { - if (reader.TryReadNil()) - { - return null; - } - - Contract.ThrowIfFalse(reader.ReadArrayHeader() == 3); - - var projectId = ProjectIdFormatter.Instance.Deserialize(ref reader, options); - Contract.ThrowIfNull(projectId); - - var id = GuidFormatter.Instance.Deserialize(ref reader, options); - var debugName = reader.ReadString(); - - return DocumentId.CreateFromSerialized(projectId, id, debugName); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public void Serialize(ref MessagePackWriter writer, DocumentId? value, MessagePackSerializerOptions options) - { - try - { - if (value is null) - { - writer.WriteNil(); - } - else - { - writer.WriteArrayHeader(3); - ProjectIdFormatter.Instance.Serialize(ref writer, value.ProjectId, options); - GuidFormatter.Instance.Serialize(ref writer, value.Id, options); - writer.Write(value.DebugName); - } - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - } - - // TODO: remove https://github.com/neuecc/MessagePack-CSharp/issues/1025 - internal sealed class EnumFormatter : IMessagePackFormatter - where TEnum : struct - { - private readonly Func _toInt; - private readonly Func _toEnum; - - static EnumFormatter() - { - var underlyingType = typeof(TEnum).GetEnumUnderlyingType(); - Contract.ThrowIfTrue(underlyingType == typeof(long) || underlyingType == typeof(ulong)); - } - - public EnumFormatter(Func toInt, Func toEnum) - { - _toInt = toInt; - _toEnum = toEnum; - } - - public TEnum Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - try - { - return _toEnum(reader.ReadInt32()); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public void Serialize(ref MessagePackWriter writer, TEnum value, MessagePackSerializerOptions options) - { - try - { - writer.WriteInt32(_toInt(value)); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public NullableEnum CreateNullable() - => new NullableEnum(_toInt, _toEnum); - - internal sealed class NullableEnum : IMessagePackFormatter - { - private readonly Func _toInt; - private readonly Func _toEnum; - - public NullableEnum(Func toInt, Func toEnum) - { - _toInt = toInt; - _toEnum = toEnum; - } - - public TEnum? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) - { - try - { - return reader.TryReadNil() ? null : _toEnum(reader.ReadInt32()); - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - - public void Serialize(ref MessagePackWriter writer, TEnum? value, MessagePackSerializerOptions options) - { - try - { - if (value == null) - { - writer.WriteNil(); - } - else - { - writer.WriteInt32(_toInt(value.Value)); - } - } - catch (Exception e) when (e is not MessagePackSerializationException) - { - throw new MessagePackSerializationException(e.Message, e); - } - } - } - } - } -} diff --git a/src/Workspaces/Remote/Core/Serialization/RoslynJsonConverter.RoslynOnly.cs b/src/Workspaces/Remote/Core/Serialization/RoslynJsonConverter.RoslynOnly.cs index d229f6378e9b1..ef2aab06fc605 100644 --- a/src/Workspaces/Remote/Core/Serialization/RoslynJsonConverter.RoslynOnly.cs +++ b/src/Workspaces/Remote/Core/Serialization/RoslynJsonConverter.RoslynOnly.cs @@ -3,9 +3,14 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.DocumentHighlighting; +using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.TodoComments; using Newtonsoft.Json; @@ -28,6 +33,13 @@ partial void AppendRoslynSpecificJsonConverters(ImmutableDictionary + { + protected override PackageSource ReadValue(JsonReader reader, JsonSerializer serializer) + { + Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject); + + var name = ReadProperty(reader); + var source = ReadProperty(reader); + + Contract.ThrowIfFalse(reader.Read()); + Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject); + + return new PackageSource(name, source); + } + + protected override void WriteValue(JsonWriter writer, PackageSource source, JsonSerializer serializer) + { + writer.WriteStartObject(); + + writer.WritePropertyName(nameof(PackageSource.Name)); + writer.WriteValue(source.Name); + + writer.WritePropertyName(nameof(PackageSource.Source)); + writer.WriteValue(source.Source); + + writer.WriteEndObject(); + } + } + private class HighlightSpanJsonConverter : BaseJsonConverter { protected override HighlightSpan ReadValue(JsonReader reader, JsonSerializer serializer) @@ -124,6 +165,113 @@ protected override void WriteValue(JsonWriter writer, HighlightSpan source, Json } } + private class PackageWithTypeResultJsonConverter : BaseJsonConverter + { + protected override PackageWithTypeResult ReadValue(JsonReader reader, JsonSerializer serializer) + { + Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject); + + var packageName = ReadProperty(reader); + var typeName = ReadProperty(reader); + var version = ReadProperty(reader); + var rank = (int)ReadProperty(reader); + var containingNamespaceNames = ReadProperty>(reader, serializer); + + Contract.ThrowIfFalse(reader.Read()); + Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject); + + return new PackageWithTypeResult(packageName, typeName, version, rank, containingNamespaceNames); + } + + protected override void WriteValue(JsonWriter writer, PackageWithTypeResult source, JsonSerializer serializer) + { + writer.WriteStartObject(); + + writer.WritePropertyName(nameof(PackageWithTypeResult.PackageName)); + writer.WriteValue(source.PackageName); + + writer.WritePropertyName(nameof(PackageWithTypeResult.TypeName)); + writer.WriteValue(source.TypeName); + + writer.WritePropertyName(nameof(PackageWithTypeResult.Version)); + writer.WriteValue(source.Version); + + writer.WritePropertyName(nameof(PackageWithTypeResult.Rank)); + writer.WriteValue(source.Rank); + + writer.WritePropertyName(nameof(PackageWithTypeResult.ContainingNamespaceNames)); + serializer.Serialize(writer, source.ContainingNamespaceNames); + + writer.WriteEndObject(); + } + } + + private class PackageWithAssemblyResultJsonConverter : BaseJsonConverter + { + protected override PackageWithAssemblyResult ReadValue(JsonReader reader, JsonSerializer serializer) + { + Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject); + + var packageName = ReadProperty(reader); + var version = ReadProperty(reader); + var rank = (int)ReadProperty(reader); + + Contract.ThrowIfFalse(reader.Read()); + Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject); + + return new PackageWithAssemblyResult(packageName, version, rank); + } + + protected override void WriteValue(JsonWriter writer, PackageWithAssemblyResult source, JsonSerializer serializer) + { + writer.WriteStartObject(); + + writer.WritePropertyName(nameof(PackageWithAssemblyResult.PackageName)); + writer.WriteValue(source.PackageName); + + writer.WritePropertyName(nameof(PackageWithAssemblyResult.Version)); + writer.WriteValue(source.Version); + + writer.WritePropertyName(nameof(PackageWithAssemblyResult.Rank)); + writer.WriteValue(source.Rank); + + writer.WriteEndObject(); + } + } + + private class ReferenceAssemblyWithTypeResultJsonConverter : BaseJsonConverter + { + protected override ReferenceAssemblyWithTypeResult ReadValue(JsonReader reader, JsonSerializer serializer) + { + Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject); + + var assemblyName = ReadProperty(reader); + var typeName = ReadProperty(reader); + var containingNamespaceNames = ReadProperty>(reader, serializer); + + Contract.ThrowIfFalse(reader.Read()); + Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject); + + return new ReferenceAssemblyWithTypeResult(assemblyName, typeName, containingNamespaceNames); + } + + protected override void WriteValue(JsonWriter writer, ReferenceAssemblyWithTypeResult source, JsonSerializer serializer) + { + writer.WriteStartObject(); + + writer.WritePropertyName(nameof(ReferenceAssemblyWithTypeResult.AssemblyName)); + writer.WriteValue(source.AssemblyName); + + writer.WritePropertyName(nameof(ReferenceAssemblyWithTypeResult.TypeName)); + writer.WriteValue(source.TypeName); + + writer.WritePropertyName(nameof(ReferenceAssemblyWithTypeResult.ContainingNamespaceNames)); + serializer.Serialize(writer, source.ContainingNamespaceNames); + + writer.WriteEndObject(); + } + } + private class TaggedTextJsonConverter : BaseJsonConverter { protected override TaggedText ReadValue(JsonReader reader, JsonSerializer serializer) @@ -153,6 +301,90 @@ protected override void WriteValue(JsonWriter writer, TaggedText source, JsonSer } } + private class AddImportFixDataJsonConverter : BaseJsonConverter + { + protected override AddImportFixData ReadValue(JsonReader reader, JsonSerializer serializer) + { + Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject); + + var kind = (AddImportFixKind)ReadProperty(reader); + var textChanges = ReadProperty>(reader, serializer).ToImmutableArrayOrEmpty(); + var title = ReadProperty(reader); + var tags = ReadProperty>(reader, serializer).ToImmutableArrayOrEmpty(); + var priority = (CodeActionPriority)ReadProperty(reader); + + var projectReferenceToAdd = ReadProperty(reader, serializer); + + var portableExecutableReferenceProjectId = ReadProperty(reader, serializer); + var portableExecutableReferenceFilePathToAdd = ReadProperty(reader); + + var assemblyReferenceAssemblyName = ReadProperty(reader); + var assemblyReferenceFullyQualifiedTypeName = ReadProperty(reader); + + var packageSource = ReadProperty(reader); + var packageName = ReadProperty(reader); + var packageVersionOpt = ReadProperty(reader); + + Contract.ThrowIfFalse(reader.Read()); + Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject); + + return kind switch + { + AddImportFixKind.ProjectSymbol => AddImportFixData.CreateForProjectSymbol(textChanges, title, tags, priority, projectReferenceToAdd), + AddImportFixKind.MetadataSymbol => AddImportFixData.CreateForMetadataSymbol(textChanges, title, tags, priority, portableExecutableReferenceProjectId, portableExecutableReferenceFilePathToAdd), + AddImportFixKind.PackageSymbol => AddImportFixData.CreateForPackageSymbol(textChanges, packageSource, packageName, packageVersionOpt), + AddImportFixKind.ReferenceAssemblySymbol => AddImportFixData.CreateForReferenceAssemblySymbol(textChanges, title, assemblyReferenceAssemblyName, assemblyReferenceFullyQualifiedTypeName), + _ => throw ExceptionUtilities.Unreachable, + }; + } + + protected override void WriteValue(JsonWriter writer, AddImportFixData source, JsonSerializer serializer) + { + writer.WriteStartObject(); + + writer.WritePropertyName(nameof(AddImportFixData.Kind)); + writer.WriteValue((int)source.Kind); + + writer.WritePropertyName(nameof(AddImportFixData.TextChanges)); + serializer.Serialize(writer, source.TextChanges ?? SpecializedCollections.EmptyList()); + + writer.WritePropertyName(nameof(AddImportFixData.Title)); + writer.WriteValue(source.Title); + + writer.WritePropertyName(nameof(AddImportFixData.Tags)); + serializer.Serialize(writer, source.Tags ?? SpecializedCollections.EmptyList()); + + writer.WritePropertyName(nameof(AddImportFixData.Priority)); + writer.WriteValue((int)source.Priority); + + writer.WritePropertyName(nameof(AddImportFixData.ProjectReferenceToAdd)); + serializer.Serialize(writer, source.ProjectReferenceToAdd); + + writer.WritePropertyName(nameof(AddImportFixData.PortableExecutableReferenceProjectId)); + serializer.Serialize(writer, source.PortableExecutableReferenceProjectId); + + writer.WritePropertyName(nameof(AddImportFixData.PortableExecutableReferenceFilePathToAdd)); + writer.WriteValue(source.PortableExecutableReferenceFilePathToAdd); + + writer.WritePropertyName(nameof(AddImportFixData.AssemblyReferenceAssemblyName)); + writer.WriteValue(source.AssemblyReferenceAssemblyName); + + writer.WritePropertyName(nameof(AddImportFixData.AssemblyReferenceFullyQualifiedTypeName)); + writer.WriteValue(source.AssemblyReferenceFullyQualifiedTypeName); + + writer.WritePropertyName(nameof(AddImportFixData.PackageSource)); + writer.WriteValue(source.PackageSource); + + writer.WritePropertyName(nameof(AddImportFixData.PackageName)); + writer.WriteValue(source.PackageName); + + writer.WritePropertyName(nameof(AddImportFixData.PackageVersionOpt)); + writer.WriteValue(source.PackageVersionOpt); + + writer.WriteEndObject(); + } + } + private class AnalyzerPerformanceInfoConverter : BaseJsonConverter { protected override AnalyzerPerformanceInfo ReadValue(JsonReader reader, JsonSerializer serializer) diff --git a/src/Workspaces/Remote/Core/ServiceDescriptor.cs b/src/Workspaces/Remote/Core/ServiceDescriptor.cs deleted file mode 100644 index ef53f79207872..0000000000000 --- a/src/Workspaces/Remote/Core/ServiceDescriptor.cs +++ /dev/null @@ -1,107 +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.IO.Pipelines; -using System.Reflection; -using MessagePack; -using MessagePack.Resolvers; -using Microsoft.ServiceHub.Framework; -using Nerdbank.Streams; -using StreamJsonRpc; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Describes Roslyn remote brokered service. - /// Adds Roslyn specific JSON converters and RPC settings to the default implementation. - /// - internal sealed class ServiceDescriptor : ServiceJsonRpcDescriptor - { - private static readonly JsonRpcTargetOptions s_jsonRpcTargetOptions = new JsonRpcTargetOptions() - { - // Do not allow JSON-RPC to automatically subscribe to events and remote their calls. - NotifyClientOfEvents = false, - - // Only allow public methods (may be on internal types) to be invoked remotely. - AllowNonPublicInvocation = false - }; - - // Enables remote APIs to pass Stream as parameter. - private static readonly MultiplexingStream.Options s_multiplexingStreamOptions = new MultiplexingStream.Options - { - ProtocolMajorVersion = 3 - }.GetFrozenCopy(); - - private ServiceDescriptor(ServiceMoniker serviceMoniker, Type? clientInterface) - : base(serviceMoniker, clientInterface, Formatters.MessagePack, MessageDelimiters.BigEndianInt32LengthHeader, s_multiplexingStreamOptions) - { - } - - private ServiceDescriptor(ServiceDescriptor copyFrom) - : base(copyFrom) - { - } - - public static ServiceDescriptor CreateRemoteServiceDescriptor(string serviceName, Type? clientInterface) - => new ServiceDescriptor(new ServiceMoniker(serviceName), clientInterface); - - public static ServiceDescriptor CreateInProcServiceDescriptor(string serviceName) - => new ServiceDescriptor(new ServiceMoniker(serviceName), clientInterface: null); - - protected override ServiceRpcDescriptor Clone() - => new ServiceDescriptor(this); - - protected override IJsonRpcMessageFormatter CreateFormatter() - => ConfigureFormatter((MessagePackFormatter)base.CreateFormatter()); - - private static readonly MessagePackSerializerOptions s_options = StandardResolverAllowPrivate.Options - .WithSecurity(MessagePackSecurity.UntrustedData.WithHashCollisionResistant(false)) - .WithResolver(CompositeResolver.Create( - MessagePackFormatters.GetFormatters(), - new IFormatterResolver[] { ImmutableCollectionMessagePackResolver.Instance, StandardResolverAllowPrivate.Instance })); - - private static MessagePackFormatter ConfigureFormatter(MessagePackFormatter formatter) - { - // See https://github.com/neuecc/messagepack-csharp. - formatter.SetMessagePackSerializerOptions(s_options); - return formatter; - } - - protected override JsonRpcConnection CreateConnection(JsonRpc jsonRpc) - { - jsonRpc.CancelLocallyInvokedMethodsWhenConnectionIsClosed = true; - var connection = base.CreateConnection(jsonRpc); - connection.LocalRpcTargetOptions = s_jsonRpcTargetOptions; - return connection; - } - - public override ServiceRpcDescriptor WithMultiplexingStream(MultiplexingStream? multiplexingStream) - { - var baseResult = base.WithMultiplexingStream(multiplexingStream); - if (baseResult is ServiceDescriptor) - return baseResult; - - // work around incorrect implementation in 16.8 Preview 2 - if (MultiplexingStream == multiplexingStream) - return this; - - var result = (ServiceDescriptor)Clone(); - typeof(ServiceRpcDescriptor).GetProperty(nameof(MultiplexingStream))!.SetValue(result, multiplexingStream); - if (result.MultiplexingStreamOptions is null) - return result; - - result = (ServiceDescriptor)result.Clone(); - typeof(ServiceJsonRpcDescriptor).GetProperty(nameof(MultiplexingStreamOptions))!.SetValue(result, value: null); - return result; - } - - internal static class TestAccessor - { - public static MessagePackSerializerOptions Options => s_options; - } - } -} diff --git a/src/Workspaces/Remote/Core/ServiceDescriptors.cs b/src/Workspaces/Remote/Core/ServiceDescriptors.cs deleted file mode 100644 index 67e83c31d1cf8..0000000000000 --- a/src/Workspaces/Remote/Core/ServiceDescriptors.cs +++ /dev/null @@ -1,99 +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.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.CodeLens; -using Microsoft.CodeAnalysis.Completion.Providers; -using Microsoft.CodeAnalysis.ConvertTupleToStruct; -using Microsoft.CodeAnalysis.DesignerAttribute; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.DocumentHighlighting; -using Microsoft.CodeAnalysis.EncapsulateField; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.NavigateTo; -using Microsoft.CodeAnalysis.ProjectTelemetry; -using Microsoft.CodeAnalysis.Rename; -using Microsoft.CodeAnalysis.SymbolSearch; -using Microsoft.CodeAnalysis.TodoComments; -using Microsoft.ServiceHub.Framework; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Service descriptors of brokered Roslyn ServiceHub services. - /// - internal static class ServiceDescriptors - { - /// - /// Brokered services must be defined in Microsoft.VisualStudio service namespace in order to be considered first party. - /// - internal const string ServiceNamePrefix = "Microsoft.VisualStudio.LanguageServices."; - - private const string InterfaceNamePrefix = "IRemote"; - private const string InterfaceNameSuffix = "Service"; - - internal static readonly ImmutableDictionary Descriptors = ImmutableDictionary.CreateRange(new[] - { - CreateDescriptors(typeof(IRemoteTodoCommentsDiscoveryService), callbackInterface: typeof(ITodoCommentsListener)), - CreateDescriptors(typeof(IRemoteDesignerAttributeDiscoveryService), callbackInterface: typeof(IDesignerAttributeListener)), - CreateDescriptors(typeof(IRemoteProjectTelemetryService), callbackInterface: typeof(IProjectTelemetryListener)), - CreateDescriptors(typeof(IRemoteDiagnosticAnalyzerService)), - CreateDescriptors(typeof(IRemoteSemanticClassificationService)), - CreateDescriptors(typeof(IRemoteSemanticClassificationCacheService)), - CreateDescriptors(typeof(IRemoteDocumentHighlightsService)), - CreateDescriptors(typeof(IRemoteEncapsulateFieldService)), - CreateDescriptors(typeof(IRemoteRenamerService)), - CreateDescriptors(typeof(IRemoteConvertTupleToStructCodeRefactoringService)), - CreateDescriptors(typeof(IRemoteSymbolFinderService), callbackInterface: typeof(IRemoteSymbolFinderService.ICallback)), - CreateDescriptors(typeof(IRemoteFindUsagesService), callbackInterface: typeof(IRemoteFindUsagesService.ICallback)), - CreateDescriptors(typeof(IRemoteNavigateToSearchService)), - CreateDescriptors(typeof(IRemoteMissingImportDiscoveryService), callbackInterface: typeof(IRemoteMissingImportDiscoveryService.ICallback)), - CreateDescriptors(typeof(IRemoteSymbolSearchUpdateService), callbackInterface: typeof(ISymbolSearchLogService)), - CreateDescriptors(typeof(IRemoteExtensionMethodImportCompletionService)), - CreateDescriptors(typeof(IRemoteDependentTypeFinderService)), - CreateDescriptors(typeof(IRemoteGlobalNotificationDeliveryService)), - CreateDescriptors(typeof(IRemoteCodeLensReferencesService)), - }); - - internal static string GetServiceName(Type serviceInterface) - { - Contract.ThrowIfFalse(serviceInterface.IsInterface); - var interfaceName = serviceInterface.Name; - Contract.ThrowIfFalse(interfaceName.StartsWith(InterfaceNamePrefix, StringComparison.Ordinal)); - Contract.ThrowIfFalse(interfaceName.EndsWith(InterfaceNameSuffix, StringComparison.Ordinal)); - - return interfaceName.Substring(InterfaceNamePrefix.Length, interfaceName.Length - InterfaceNamePrefix.Length - InterfaceNameSuffix.Length); - } - - internal static string GetQualifiedServiceName(Type serviceInterface) - => ServiceNamePrefix + GetServiceName(serviceInterface); - - private static KeyValuePair CreateDescriptors(Type serviceInterface, Type? callbackInterface = null) - { - Contract.ThrowIfFalse(callbackInterface == null || callbackInterface.IsInterface); - - var serviceName = GetQualifiedServiceName(serviceInterface); - var descriptor32 = ServiceDescriptor.CreateRemoteServiceDescriptor(serviceName, callbackInterface); - var descriptor64 = ServiceDescriptor.CreateRemoteServiceDescriptor(serviceName + RemoteServiceName.Suffix64, callbackInterface); - return new(serviceInterface, (descriptor32, descriptor64)); - } - - public static ServiceRpcDescriptor GetServiceDescriptor(Type serviceType, bool isRemoteHost64Bit) - { - var (descriptor32, descriptor64) = Descriptors[serviceType]; - return isRemoteHost64Bit ? descriptor64 : descriptor32; - } - - internal static string GetFeatureName(Type serviceInterface) - => RemoteWorkspacesResources.GetResourceString("FeatureName_" + GetServiceName(serviceInterface)); - } -} diff --git a/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs b/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs index 826ebbcbd3216..6c06e69287adb 100644 --- a/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs +++ b/src/Workspaces/Remote/Core/ServiceHubRemoteHostClient.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Telemetry; using Microsoft.ServiceHub.Client; -using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; using StreamJsonRpc; @@ -34,8 +33,6 @@ internal sealed partial class ServiceHubRemoteHostClient : RemoteHostClient, IRe private readonly ISerializerService _serializer; private readonly RemoteEndPoint _endPoint; private readonly HubClient _hubClient; - private readonly IServiceBroker _serviceBroker; - private readonly ServiceBrokerClient _serviceBrokerClient; private readonly IErrorReportingService? _errorReportingService; private readonly IRemoteHostClientShutdownCancellationService? _shutdownCancellationService; @@ -43,8 +40,6 @@ internal sealed partial class ServiceHubRemoteHostClient : RemoteHostClient, IRe private ServiceHubRemoteHostClient( HostWorkspaceServices services, - IServiceBroker serviceBroker, - ServiceBrokerClient serviceBrokerClient, HubClient hubClient, Stream stream) { @@ -56,8 +51,6 @@ private ServiceHubRemoteHostClient( services.GetService()?.RegisterUnexpectedExceptionLogger(hubClient.Logger); _services = services; - _serviceBroker = serviceBroker; - _serviceBrokerClient = serviceBrokerClient; _hubClient = hubClient; _endPoint = new RemoteEndPoint(stream, hubClient.Logger, incomingCallTarget: this); @@ -74,22 +67,17 @@ private ServiceHubRemoteHostClient( private void OnUnexpectedExceptionThrown(Exception unexpectedException) => _errorReportingService?.ShowRemoteHostCrashedErrorInfo(unexpectedException); - public static async Task CreateAsync(HostWorkspaceServices services, IServiceBroker serviceBroker, CancellationToken cancellationToken) + public static async Task CreateAsync(HostWorkspaceServices services, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.ServiceHubRemoteHostClient_CreateAsync, KeyValueLogMessage.NoProperty, cancellationToken)) { Logger.Log(FunctionId.RemoteHost_Bitness, KeyValueLogMessage.Create(LogType.Trace, m => m["64bit"] = RemoteHostOptions.IsServiceHubProcess64Bit(services))); -#pragma warning disable ISB001 // Dispose of proxies -#pragma warning disable VSTHRD012 // Provide JoinableTaskFactory where allowed - var serviceBrokerClient = new ServiceBrokerClient(serviceBroker); -#pragma warning restore - var hubClient = new HubClient("ManagedLanguage.IDE.RemoteHostClient"); var remoteHostStream = await RequestServiceAsync(services, hubClient, WellKnownServiceHubService.RemoteHost, cancellationToken).ConfigureAwait(false); - var client = new ServiceHubRemoteHostClient(services, serviceBroker, serviceBrokerClient, hubClient, remoteHostStream); + var client = new ServiceHubRemoteHostClient(services, hubClient, remoteHostStream); var uiCultureLCID = CultureInfo.CurrentUICulture.LCID; var cultureLCID = CultureInfo.CurrentCulture.LCID; @@ -150,36 +138,6 @@ static bool ReportNonFatalWatson(Exception e, CancellationToken cancellationToke } } - public override async ValueTask> CreateConnectionAsync(object? callbackTarget, CancellationToken cancellationToken) - { - try - { - var options = default(ServiceActivationOptions); - - if (callbackTarget is not null) - { - options.ClientRpcTarget = callbackTarget; - } - - var descriptor = ServiceDescriptors.GetServiceDescriptor(typeof(T), RemoteHostOptions.IsServiceHubProcess64Bit(_services)); - - // Make sure we are on the thread pool to avoid UI thread dependencies if external code uses ConfigureAwait(true) - await TaskScheduler.Default; - -#pragma warning disable ISB001 // Dispose of proxies - BrokeredServiceConnection takes care of disposal - var proxy = await _serviceBroker.GetProxyAsync(descriptor, options, cancellationToken).ConfigureAwait(false); -#pragma warning restore - - Contract.ThrowIfNull(proxy, $"Brokered service not found: {descriptor.Moniker.Name}"); - - return new BrokeredServiceConnection(proxy, _assetStorage, _errorReportingService, _shutdownCancellationService); - } - catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceledAndPropagate(e)) - { - throw ExceptionUtilities.Unreachable; - } - } - public override Task CreateConnectionAsync(RemoteServiceName serviceName, object? callbackTarget, CancellationToken cancellationToken) { // When callbackTarget is given, we can't share/pool connection since callbackTarget attaches a state to connection. @@ -211,8 +169,6 @@ public override void Dispose() _services.GetService()?.UnregisterUnexpectedExceptionLogger(_hubClient.Logger); _hubClient.Dispose(); - _serviceBrokerClient.Dispose(); - base.Dispose(); } diff --git a/src/Workspaces/Remote/Core/SolutionAssetProvider.cs b/src/Workspaces/Remote/Core/SolutionAssetProvider.cs deleted file mode 100644 index 54de81bf91f4c..0000000000000 --- a/src/Workspaces/Remote/Core/SolutionAssetProvider.cs +++ /dev/null @@ -1,111 +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.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Pipelines; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Experiments; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Serialization; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; -using Nerdbank.Streams; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class SolutionAssetProvider : ISolutionAssetProvider - { - public const string ServiceName = ServiceDescriptors.ServiceNamePrefix + "SolutionAssetProvider"; - - internal static ServiceDescriptor ServiceDescriptor { get; } = ServiceDescriptor.CreateInProcServiceDescriptor(ServiceName); - - private readonly HostWorkspaceServices _services; - - public SolutionAssetProvider(HostWorkspaceServices services) - { - _services = services; - } - - public async ValueTask GetAssetsAsync(PipeWriter pipeWriter, int scopeId, Checksum[] checksums, CancellationToken cancellationToken) - { - var assetStorage = _services.GetRequiredService().AssetStorage; - var serializer = _services.GetRequiredService(); - - SolutionAsset? singleAsset = null; - IReadOnlyDictionary? assetMap = null; - - if (checksums.Length == 1) - { - singleAsset = (await assetStorage.GetAssetAsync(scopeId, checksums[0], cancellationToken).ConfigureAwait(false)) ?? SolutionAsset.Null; - } - else - { - assetMap = await assetStorage.GetAssetsAsync(scopeId, checksums, cancellationToken).ConfigureAwait(false); - } - - // We can cancel early, but once the pipe operations are scheduled we rely on both operations running to - // avoid deadlocks (the exception handler in 'task1' ensures progress is made in 'task2'). - cancellationToken.ThrowIfCancellationRequested(); - var mustNotCancelToken = CancellationToken.None; - - // Work around the lack of async stream writing in ObjectWriter, which is required when writing to the RPC pipe. - // Run two tasks - the first synchronously writes to a local pipe and the second asynchronosly transfers the data to the RPC pipe. - // - // Configure the pipe to never block on write (waiting for the reader to read). This prevents deadlocks but might result in more - // (non-contiguous) memory allocated for the underlying buffers. The amount of memory is bounded by the total size of the serialized assets. - var localPipe = new Pipe(RemoteHostAssetSerialization.PipeOptionsWithUnlimitedWriterBuffer); - - var task1 = Task.Run(() => - { - try - { - var stream = localPipe.Writer.AsStream(leaveOpen: false); - using var writer = new ObjectWriter(stream, leaveOpen: false, cancellationToken); - RemoteHostAssetSerialization.WriteData(writer, singleAsset, assetMap, serializer, scopeId, checksums, cancellationToken); - } - catch (Exception e) when (FatalError.ReportWithoutCrashUnlessCanceled(e, cancellationToken)) - { - // no-op - } - }, mustNotCancelToken); - - // Complete RPC once we send the initial piece of data and start waiting for the writer to send more, - // so the client can start reading from the stream. Once CopyPipeDataAsync completes the pipeWriter - // the corresponding client-side pipeReader will complete and the data transfer will be finished. - var task2 = CopyPipeDataAsync(); - - await Task.WhenAll(task1, task2).ConfigureAwait(false); - - async Task CopyPipeDataAsync() - { - Exception? exception = null; - try - { - await localPipe.Reader.CopyToAsync(pipeWriter, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) - { - FatalError.ReportWithoutCrashUnlessCanceled(e, cancellationToken); - exception = e; - } - finally - { - await localPipe.Reader.CompleteAsync(exception).ConfigureAwait(false); - await pipeWriter.CompleteAsync(exception).ConfigureAwait(false); - } - } - } - - public ValueTask IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) - => new ValueTask(_services.GetRequiredService().IsExperimentEnabled(experimentName)); - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Host/IAssetSource.cs b/src/Workspaces/Remote/ServiceHub/Host/IAssetSource.cs index 6401edc33c6d9..332d1e24dda11 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/IAssetSource.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/IAssetSource.cs @@ -17,9 +17,9 @@ namespace Microsoft.CodeAnalysis.Remote /// internal interface IAssetSource { - ValueTask> GetAssetsAsync(int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken); + Task> GetAssetsAsync(int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken); // TODO: remove (https://github.com/dotnet/roslyn/issues/43477) - ValueTask IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken); + Task IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs b/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs deleted file mode 100644 index 7ad7c7e8d7284..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Host/SolutionAssetSource.cs +++ /dev/null @@ -1,55 +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.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Serialization; -using Microsoft.ServiceHub.Framework; -using Microsoft.VisualStudio.Threading; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class SolutionAssetSource : IAssetSource - { - private readonly ServiceBrokerClient _client; - - public SolutionAssetSource(ServiceBrokerClient client) - { - _client = client; - } - - public async ValueTask> GetAssetsAsync(int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) - { - // Make sure we are on the thread pool to avoid UI thread dependencies if external code uses ConfigureAwait(true) - await TaskScheduler.Default; - - using var provider = await _client.GetProxyAsync(SolutionAssetProvider.ServiceDescriptor, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(provider.Proxy); - - return await new RemoteCallback(provider.Proxy).InvokeAsync( - (proxy, pipeWriter, cancellationToken) => proxy.GetAssetsAsync(pipeWriter, scopeId, checksums.ToArray(), cancellationToken), - (pipeReader, cancellationToken) => RemoteHostAssetSerialization.ReadDataAsync(pipeReader, scopeId, checksums, serializerService, cancellationToken), - cancellationToken).ConfigureAwait(false); - } - - public async ValueTask IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) - { - // Make sure we are on the thread pool to avoid UI thread dependencies if external code uses ConfigureAwait(true) - await TaskScheduler.Default; - - using var provider = await _client.GetProxyAsync(SolutionAssetProvider.ServiceDescriptor, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(provider.Proxy); - - return await new RemoteCallback(provider.Proxy).InvokeAsync( - (self, cancellationToken) => provider.Proxy.IsExperimentEnabledAsync(experimentName, cancellationToken), - cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs deleted file mode 100644 index 429f4a2ebe2d0..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs +++ /dev/null @@ -1,112 +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.IO; -using System.IO.Pipelines; -using System.Threading.Tasks; -using Microsoft.ServiceHub.Framework; -using Microsoft.ServiceHub.Framework.Services; -using Nerdbank.Streams; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal abstract partial class BrokeredServiceBase - { - internal interface IFactory - { - object Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker); - Type ServiceType { get; } - } - - internal abstract class FactoryBase : IServiceHubServiceFactory, IFactory - where TService : class - { - static FactoryBase() - { - Debug.Assert(typeof(TService).IsInterface); - } - - protected abstract TService CreateService(in ServiceConstructionArguments arguments); - - protected virtual TService CreateService( - in ServiceConstructionArguments arguments, - ServiceRpcDescriptor descriptor, - ServiceRpcDescriptor.RpcConnection serverConnection, - object? clientRpcTarget) - => CreateService(arguments); - - public Task CreateAsync( - Stream stream, - IServiceProvider hostProvidedServices, - ServiceActivationOptions serviceActivationOptions, - IServiceBroker serviceBroker, - AuthorizationServiceClient? authorizationServiceClient) - { - // Dispose the AuthorizationServiceClient since we won't be using it - authorizationServiceClient?.Dispose(); - - return Task.FromResult((object)Create( - stream.UsePipe(), - hostProvidedServices, - serviceActivationOptions, - serviceBroker)); - } - - object IFactory.Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker) - => Create(pipe, hostProvidedServices, serviceActivationOptions, serviceBroker); - - Type IFactory.ServiceType => typeof(TService); - - internal TService Create( - IDuplexPipe pipe, - IServiceProvider hostProvidedServices, - ServiceActivationOptions serviceActivationOptions, - IServiceBroker serviceBroker) - { - var descriptor = ServiceDescriptors.GetServiceDescriptor(typeof(TService), isRemoteHost64Bit: IntPtr.Size == 8); - var serviceHubTraceSource = (TraceSource)hostProvidedServices.GetService(typeof(TraceSource)); - var serverConnection = descriptor.WithTraceSource(serviceHubTraceSource).ConstructRpcConnection(pipe); - - var args = new ServiceConstructionArguments(hostProvidedServices, serviceBroker); - var service = CreateService(args, descriptor, serverConnection, serviceActivationOptions.ClientRpcTarget); - - serverConnection.AddLocalRpcTarget(service); - serverConnection.StartListening(); - - return service; - } - } - - internal abstract class FactoryBase : FactoryBase - where TService : class - where TCallback : class - { - static FactoryBase() - { - Debug.Assert(typeof(TCallback).IsInterface); - } - - protected abstract TService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback); - - protected sealed override TService CreateService(in ServiceConstructionArguments arguments) - => throw ExceptionUtilities.Unreachable; - - protected sealed override TService CreateService( - in ServiceConstructionArguments arguments, - ServiceRpcDescriptor descriptor, - ServiceRpcDescriptor.RpcConnection serverConnection, - object? clientRpcTarget) - { - Contract.ThrowIfNull(descriptor.ClientInterface); - var callback = (TCallback)(clientRpcTarget ?? serverConnection.ConstructRpcClient(descriptor.ClientInterface)); - return CreateService(arguments, new RemoteCallback(callback)); - } - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs deleted file mode 100644 index 43eab4ac84356..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs +++ /dev/null @@ -1,26 +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 Microsoft.ServiceHub.Framework; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal abstract partial class BrokeredServiceBase - { - internal readonly struct ServiceConstructionArguments - { - public readonly IServiceProvider ServiceProvider; - public readonly IServiceBroker ServiceBroker; - - public ServiceConstructionArguments(IServiceProvider serviceProvider, IServiceBroker serviceBroker) - { - ServiceProvider = serviceProvider; - ServiceBroker = serviceBroker; - } - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs deleted file mode 100644 index 5ee6d4037c966..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs +++ /dev/null @@ -1,93 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.ServiceHub.Framework; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - /// - /// Base type for Roslyn brokered services hosted in ServiceHub. - /// - internal abstract partial class BrokeredServiceBase : IDisposable - { - private readonly TraceSource _logger; - protected readonly RemoteWorkspaceManager WorkspaceManager; - - protected readonly SolutionAssetSource SolutionAssetSource; - protected readonly ServiceBrokerClient ServiceBrokerClient; - - // test data are only available when running tests: - internal readonly RemoteHostTestData? TestData; - - static BrokeredServiceBase() - { - } - - protected BrokeredServiceBase(in ServiceConstructionArguments arguments) - { - _logger = (TraceSource)arguments.ServiceProvider.GetService(typeof(TraceSource)); - - TestData = (RemoteHostTestData?)arguments.ServiceProvider.GetService(typeof(RemoteHostTestData)); - WorkspaceManager = TestData?.WorkspaceManager ?? RemoteWorkspaceManager.Default; - -#pragma warning disable VSTHRD012 // Provide JoinableTaskFactory where allowed - ServiceBrokerClient = new ServiceBrokerClient(arguments.ServiceBroker); -#pragma warning restore - - SolutionAssetSource = new SolutionAssetSource(ServiceBrokerClient); - } - - public void Dispose() - => ServiceBrokerClient.Dispose(); - - public RemoteWorkspace GetWorkspace() - => WorkspaceManager.GetWorkspace(); - - protected void Log(TraceEventType errorType, string message) - => _logger.TraceEvent(errorType, 0, $"{GetType()}: {message}"); - - protected Task GetSolutionAsync(PinnedSolutionInfo solutionInfo, CancellationToken cancellationToken) - { - var workspace = GetWorkspace(); - var assetProvider = workspace.CreateAssetProvider(solutionInfo, WorkspaceManager.SolutionAssetCache, SolutionAssetSource); - return workspace.GetSolutionAsync(assetProvider, solutionInfo.SolutionChecksum, solutionInfo.FromPrimaryBranch, solutionInfo.WorkspaceVersion, cancellationToken); - } - - protected async ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) - { - WorkspaceManager.SolutionAssetCache.UpdateLastActivityTime(); - - try - { - return await implementation(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportWithoutCrashUnlessCanceledAndPropagate(ex, cancellationToken)) - { - throw ExceptionUtilities.Unreachable; - } - } - - protected async ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) - { - WorkspaceManager.SolutionAssetCache.UpdateLastActivityTime(); - - try - { - await implementation(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportWithoutCrashUnlessCanceledAndPropagate(ex, cancellationToken)) - { - throw ExceptionUtilities.Unreachable; - } - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService.cs new file mode 100644 index 0000000000000..600a70a4c4a35 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService.cs @@ -0,0 +1,24 @@ +// 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.IO; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.Remote +{ + // root level service for all Roslyn services + internal partial class CodeAnalysisService : ServiceBase + { + private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache; + + public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) + : base(serviceProvider, stream) + { + _analyzerInfoCache = new DiagnosticAnalyzerInfoCache(); + + StartService(); + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_AddImport.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_AddImport.cs new file mode 100644 index 0000000000000..bf164fb7dd028 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_AddImport.cs @@ -0,0 +1,91 @@ +// 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.AddImport; +using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.SymbolSearch; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Remote +{ + internal partial class CodeAnalysisService : IRemoteAddImportFeatureService + { + public Task> GetFixesAsync( + PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, bool placeSystemNamespaceFirst, + bool searchReferenceAssemblies, IList packageSources, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (UserOperationBooster.Boost()) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var document = solution.GetDocument(documentId); + + var service = document.GetLanguageService(); + + var symbolSearchService = new SymbolSearchService(EndPoint); + + var result = await service.GetFixesAsync( + document, span, diagnosticId, maxResults, placeSystemNamespaceFirst, + symbolSearchService, searchReferenceAssemblies, + packageSources.ToImmutableArray(), cancellationToken).ConfigureAwait(false); + + return (IList)result; + } + }, cancellationToken); + } + + /// + /// Provides an implementation of the ISymbolSearchService on the remote side so that + /// Add-Import can find results in nuget packages/reference assemblies. This works + /// by remoting *from* the OOP server back to the host, which can then forward this + /// appropriately to wherever the real ISymbolSearchService is running. This is necessary + /// because it's not guaranteed that the real ISymbolSearchService will be running in + /// the same process that is supplying the . + /// + /// Ideally we would not need to bounce back to the host for this. + /// + private sealed class SymbolSearchService : ISymbolSearchService + { + private readonly RemoteEndPoint _endPoint; + + public SymbolSearchService(RemoteEndPoint endPoint) + { + _endPoint = endPoint; + } + + public async Task> FindPackagesWithTypeAsync( + string source, string name, int arity, CancellationToken cancellationToken) + { + return await _endPoint.InvokeAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithTypeAsync), + new object[] { source, name, arity }, + cancellationToken).ConfigureAwait(false); + } + + public async Task> FindPackagesWithAssemblyAsync( + string source, string assemblyName, CancellationToken cancellationToken) + { + return await _endPoint.InvokeAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindPackagesWithAssemblyAsync), + new object[] { source, assemblyName }, + cancellationToken).ConfigureAwait(false); + } + + public async Task> FindReferenceAssembliesWithTypeAsync( + string name, int arity, CancellationToken cancellationToken) + { + return await _endPoint.InvokeAsync>( + nameof(IRemoteSymbolSearchUpdateEngine.FindReferenceAssembliesWithTypeAsync), + new object[] { name, arity }, + cancellationToken).ConfigureAwait(false); + } + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_CodeLens.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_CodeLens.cs new file mode 100644 index 0000000000000..915be2110b99e --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_CodeLens.cs @@ -0,0 +1,108 @@ +// 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.CodeLens; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Remote +{ + internal partial class CodeAnalysisService : IRemoteCodeLensReferencesService + { + public Task GetReferenceCountAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_GetReferenceCountAsync, documentId.ProjectId.DebugName, cancellationToken)) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + + var document = solution.GetDocument(documentId); + if (document == null) + { + return null; + } + + var syntaxNode = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)).FindNode(textSpan); + + return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync( + solution, + documentId, + syntaxNode, + maxResultCount, + cancellationToken).ConfigureAwait(false); + } + }, cancellationToken); + } + + public Task> FindReferenceLocationsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceLocationsAsync, documentId.ProjectId.DebugName, cancellationToken)) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var document = solution.GetDocument(documentId); + if (document == null) + { + return null; + } + + var syntaxNode = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)).FindNode(textSpan); + + return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync( + solution, + documentId, + syntaxNode, + cancellationToken).ConfigureAwait(false); + } + }, cancellationToken); + } + + public Task> FindReferenceMethodsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceMethodsAsync, documentId.ProjectId.DebugName, cancellationToken)) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var document = solution.GetDocument(documentId); + if (document == null) + { + return null; + } + + var syntaxNode = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)).FindNode(textSpan); + + return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync(solution, documentId, + syntaxNode, cancellationToken).ConfigureAwait(false); + } + }, cancellationToken); + } + + public Task GetFullyQualifiedNameAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (Internal.Log.Logger.LogBlock(FunctionId.CodeAnalysisService_GetFullyQualifiedName, documentId.ProjectId.DebugName, cancellationToken)) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var document = solution.GetDocument(documentId); + if (document == null) + { + return null; + } + + var syntaxNode = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)).FindNode(textSpan); + + return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedNameAsync(solution, documentId, + syntaxNode, cancellationToken).ConfigureAwait(false); + } + }, cancellationToken); + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ConvertTupleToStruct.cs similarity index 79% rename from src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ConvertTupleToStruct.cs index bcd14f8fd13be..c4ce24152653f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ConvertTupleToStruct.cs @@ -12,27 +12,17 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteConvertTupleToStructCodeRefactoringService : BrokeredServiceBase, IRemoteConvertTupleToStructCodeRefactoringService + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteConvertTupleToStructCodeRefactoringProvider { - internal sealed class Factory : FactoryBase - { - protected override IRemoteConvertTupleToStructCodeRefactoringService CreateService(in ServiceConstructionArguments arguments) - => new RemoteConvertTupleToStructCodeRefactoringService(arguments); - } - - public RemoteConvertTupleToStructCodeRefactoringService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask ConvertToStructAsync( + public Task ConvertToStructAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, Scope scope, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -49,7 +39,11 @@ public ValueTask ConvertToStructAsync( var renamedToken = await GetRenamedTokenAsync( solution, cleanedSolution, cancellationToken).ConfigureAwait(false); - return new SerializableConvertTupleToStructResult(documentTextChanges, renamedToken); + return new SerializableConvertTupleToStructResult + { + DocumentTextChanges = documentTextChanges, + RenamedToken = renamedToken, + }; } }, cancellationToken); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DependentTypeFinder.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DependentTypeFinder.cs new file mode 100644 index 0000000000000..771c89b83b303 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DependentTypeFinder.cs @@ -0,0 +1,84 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindSymbols; + +namespace Microsoft.CodeAnalysis.Remote +{ + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteDependentTypeFinder + { + private Task> FindTypesAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId typeAndProjectId, + ProjectId[] projectIds, + Func, Task>> func, + CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (UserOperationBooster.Boost()) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + + var symbol = await typeAndProjectId.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); + + if (!(symbol is INamedTypeSymbol namedType)) + return ImmutableArray.Empty; + + var projects = projectIds?.Select(id => solution.GetProject(id)).ToImmutableHashSet(); + var types = await func(namedType, solution, projects).ConfigureAwait(false); + + return types.SelectAsArray( + t => SerializableSymbolAndProjectId.Dehydrate(solution, t, cancellationToken)); + } + }, cancellationToken); + } + + public Task> FindDerivedClassesAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId typeAndProjectId, + ProjectId[] projectIds, + bool transitive, + CancellationToken cancellationToken) + { + return FindTypesAsync( + solutionInfo, typeAndProjectId, projectIds, + (nt, s, ps) => DependentTypeFinder.FindDerivedClassesAsync(nt, s, ps, transitive, cancellationToken), + cancellationToken); + } + + public Task> FindDerivedInterfacesAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId typeAndProjectId, + ProjectId[] projectIds, + bool transitive, + CancellationToken cancellationToken) + { + return FindTypesAsync( + solutionInfo, typeAndProjectId, projectIds, + (nt, s, ps) => DependentTypeFinder.FindDerivedInterfacesAsync(nt, s, ps, transitive, cancellationToken), + cancellationToken); + } + + public Task> FindImplementingTypesAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId typeAndProjectId, + ProjectId[] projectIds, + bool transitive, + CancellationToken cancellationToken) + { + return FindTypesAsync( + solutionInfo, typeAndProjectId, projectIds, + (nt, s, ps) => DependentTypeFinder.FindImplementingTypesAsync(nt, s, ps, transitive, cancellationToken), + cancellationToken); + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Diagnostics.cs similarity index 59% rename from src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Diagnostics.cs index db6e958bb1924..2da0f2207e544 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Diagnostics.cs @@ -2,46 +2,28 @@ // 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.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Remote.Diagnostics; -using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteDiagnosticAnalyzerService : BrokeredServiceBase, IRemoteDiagnosticAnalyzerService + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteDiagnosticAnalyzerService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDiagnosticAnalyzerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDiagnosticAnalyzerService(arguments); - } - - private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache = new(); - - public RemoteDiagnosticAnalyzerService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - /// /// Calculate dignostics. this works differently than other ones such as todo comments or designer attribute scanner /// since in proc and out of proc runs quite differently due to concurrency and due to possible amount of data /// that needs to pass through between processes /// - public ValueTask CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, CancellationToken cancellationToken) + public Task CalculateDiagnosticsAsync(PinnedSolutionInfo solutionInfo, DiagnosticArguments arguments, string pipeName, CancellationToken cancellationToken) { - // Complete RPC right away so the client can start reading from the stream. - // The fire-and forget task starts writing to the output stream and the client will read it until it reads all expected data. - - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectId.DebugName, cancellationToken)) using (arguments.IsHighPriority ? UserOperationBooster.Boost() : default) @@ -62,20 +44,22 @@ public ValueTask CalculateDiagnosticsAsyn getTelemetryInfo: arguments.GetTelemetryInfo, cancellationToken).ConfigureAwait(false); - // save log for debugging - var diagnosticCount = result.Diagnostics.Sum( - entry => entry.diagnosticMap.Syntax.Length + entry.diagnosticMap.Semantic.Length + entry.diagnosticMap.NonLocal.Length + entry.diagnosticMap.Other.Length); + await RemoteEndPoint.WriteDataToNamedPipeAsync(pipeName, (result, documentAnalysisKind), (writer, data, cancellationToken) => + { + var (diagnostics, telemetry) = DiagnosticResultSerializer.WriteDiagnosticAnalysisResults(writer, data.documentAnalysisKind, data.result, cancellationToken); - Log(TraceEventType.Information, $"diagnostics: {diagnosticCount}, telemetry: {result.Telemetry.Length}"); + // save log for debugging + Log(TraceEventType.Information, $"diagnostics: {diagnostics}, telemetry: {telemetry}"); - return result; + return Task.CompletedTask; + }, cancellationToken).ConfigureAwait(false); } }, cancellationToken); } - public ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray snapshot, int unitCount, CancellationToken cancellationToken) + public void ReportAnalyzerPerformance(List snapshot, int unitCount, CancellationToken cancellationToken) { - return RunServiceAsync(cancellationToken => + RunService(() => { using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_ReportAnalyzerPerformance, cancellationToken)) { @@ -84,13 +68,11 @@ public ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray(); if (service == null) { - return default; + return; } service.AddSnapshot(snapshot, unitCount); } - - return default; }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DocumentHighlights.cs similarity index 64% rename from src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DocumentHighlights.cs index d4caad616c126..a2b4601e6c50f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_DocumentHighlights.cs @@ -13,23 +13,13 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteDocumentHighlightsService : BrokeredServiceBase, IRemoteDocumentHighlightsService + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteDocumentHighlights { - internal sealed class Factory : FactoryBase + public Task> GetDocumentHighlightsAsync( + PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, DocumentId[] documentIdsToSearch, CancellationToken cancellationToken) { - protected override IRemoteDocumentHighlightsService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDocumentHighlightsService(arguments); - } - - public RemoteDocumentHighlightsService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask> GetDocumentHighlightsAsync( - PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, ImmutableArray documentIdsToSearch, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { // NOTE: In projection scenarios, we might get a set of documents to search // that are not all the same language and might not exist in the OOP process @@ -44,7 +34,7 @@ public ValueTask> GetDocumentHigh var result = await service.GetDocumentHighlightsAsync( document, position, documentsToSearch, cancellationToken).ConfigureAwait(false); - return result.SelectAsArray(SerializableDocumentHighlights.Dehydrate); + return (IList)result.SelectAsArray(SerializableDocumentHighlights.Dehydrate); }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_EncapsulateField.cs similarity index 72% rename from src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_EncapsulateField.cs index c3fff04d4c712..d309993ea20de 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_EncapsulateField.cs @@ -13,27 +13,16 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteEncapsulateFieldService : BrokeredServiceBase, IRemoteEncapsulateFieldService + internal partial class CodeAnalysisService : IRemoteEncapsulateFieldService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteEncapsulateFieldService CreateService(in ServiceConstructionArguments arguments) - => new RemoteEncapsulateFieldService(arguments); - } - - public RemoteEncapsulateFieldService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask)>> EncapsulateFieldsAsync( + public Task<(DocumentId, TextChange[])[]> EncapsulateFieldsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, ImmutableArray fieldSymbolKeys, bool updateReferences, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -47,7 +36,7 @@ public RemoteEncapsulateFieldService(in ServiceConstructionArguments arguments) { var resolved = SymbolKey.ResolveString(key, compilation, cancellationToken: cancellationToken).GetAnySymbol() as IFieldSymbol; if (resolved == null) - return ImmutableArray<(DocumentId, ImmutableArray)>.Empty; + return Array.Empty<(DocumentId, TextChange[])>(); fields.Add(resolved); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ExtensionMethodFiltering.cs similarity index 60% rename from src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ExtensionMethodFiltering.cs index bff5264a82c83..cdf9ef9bf5cda 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_ExtensionMethodFiltering.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion.Providers; @@ -15,29 +14,18 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteExtensionMethodImportCompletionService : BrokeredServiceBase, IRemoteExtensionMethodImportCompletionService + internal partial class CodeAnalysisService : IRemoteExtensionMethodImportCompletionService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteExtensionMethodImportCompletionService CreateService(in ServiceConstructionArguments arguments) - => new RemoteExtensionMethodImportCompletionService(arguments); - } - - public RemoteExtensionMethodImportCompletionService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask GetUnimportedExtensionMethodsAsync( + public Task<(IList, StatisticCounter)> GetUnimportedExtensionMethodsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, int position, string receiverTypeSymbolKeyData, - ImmutableArray namespaceInScope, + string[] namespaceInScope, bool forceIndexCreation, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -51,11 +39,12 @@ public ValueTask GetUnimportedExtensionM var syntaxFacts = document.GetRequiredLanguageService(); var namespaceInScopeSet = new HashSet(namespaceInScope, syntaxFacts.StringComparer); - return await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsInCurrentProcessAsync( + var (items, counter) = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsInCurrentProcessAsync( document, position, receiverTypeSymbol, namespaceInScopeSet, forceIndexCreation, cancellationToken).ConfigureAwait(false); + return ((IList)items, counter); } - return new SerializableUnimportedExtensionMethods(ImmutableArray.Empty, isPartialResult: false, getSymbolsTicks: 0, createItemsTicks: 0); + return (Array.Empty(), new StatisticCounter()); } }, cancellationToken); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_FindUsages.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_FindUsages.cs new file mode 100644 index 0000000000000..2817122d3d28d --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_FindUsages.cs @@ -0,0 +1,145 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.FindUsages; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.Remote +{ + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteFindUsagesService + { + public Task FindReferencesAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId symbolAndProjectIdArg, + SerializableFindReferencesSearchOptions options, + CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (UserOperationBooster.Boost()) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var project = solution.GetProject(symbolAndProjectIdArg.ProjectId); + + var symbol = await symbolAndProjectIdArg.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); + + if (symbol == null) + return; + + var context = new RemoteFindUsageContext(solution, EndPoint, cancellationToken); + await AbstractFindUsagesService.FindReferencesAsync( + context, symbol, project, options.Rehydrate()).ConfigureAwait(false); + } + }, cancellationToken); + } + + public Task FindImplementationsAsync( + PinnedSolutionInfo solutionInfo, + SerializableSymbolAndProjectId symbolAndProjectIdArg, + CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + using (UserOperationBooster.Boost()) + { + var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); + var project = solution.GetProject(symbolAndProjectIdArg.ProjectId); + + var symbol = await symbolAndProjectIdArg.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); + if (symbol == null) + return; + + var context = new RemoteFindUsageContext(solution, EndPoint, cancellationToken); + await AbstractFindUsagesService.FindImplementationsAsync( + symbol, project, context).ConfigureAwait(false); + } + }, cancellationToken); + } + + private class RemoteFindUsageContext : IFindUsagesContext, IStreamingProgressTracker + { + private readonly Solution _solution; + private readonly RemoteEndPoint _endPoint; + private readonly Dictionary _definitionItemToId = new Dictionary(); + + public CancellationToken CancellationToken { get; } + + public RemoteFindUsageContext(Solution solution, RemoteEndPoint endPoint, CancellationToken cancellationToken) + { + _solution = solution; + _endPoint = endPoint; + CancellationToken = cancellationToken; + } + + #region IStreamingProgressTracker + + public Task AddItemsAsync(int count) + => _endPoint.InvokeAsync(nameof(AddItemsAsync), new object[] { count }, CancellationToken); + + public Task ItemCompletedAsync() + => _endPoint.InvokeAsync(nameof(ItemCompletedAsync), Array.Empty(), CancellationToken); + + #endregion + + #region IFindUsagesContext + + public IStreamingProgressTracker ProgressTracker => this; + + public async ValueTask ReportMessageAsync(string message) + => await _endPoint.InvokeAsync(nameof(ReportMessageAsync), new object[] { message }, CancellationToken).ConfigureAwait(false); + + public async ValueTask ReportProgressAsync(int current, int maximum) + => await _endPoint.InvokeAsync(nameof(ReportProgressAsync), new object[] { current, maximum }, CancellationToken).ConfigureAwait(false); + + public async ValueTask SetSearchTitleAsync(string title) + => await _endPoint.InvokeAsync(nameof(SetSearchTitleAsync), new object[] { title }, CancellationToken).ConfigureAwait(false); + + public async ValueTask OnDefinitionFoundAsync(DefinitionItem definition) + { + var id = GetOrAddDefinitionItemId(definition); + await _endPoint.InvokeAsync(nameof(OnDefinitionFoundAsync), + new object[] + { + SerializableDefinitionItem.Dehydrate(id, definition), + }, + CancellationToken).ConfigureAwait(false); + } + + private int GetOrAddDefinitionItemId(DefinitionItem item) + { + lock (_definitionItemToId) + { + if (!_definitionItemToId.TryGetValue(item, out var id)) + { + id = _definitionItemToId.Count; + _definitionItemToId.Add(item, id); + } + + return id; + } + } + + public async ValueTask OnReferenceFoundAsync(SourceReferenceItem reference) + { + var definitionItem = GetOrAddDefinitionItemId(reference.Definition); + await _endPoint.InvokeAsync(nameof(OnReferenceFoundAsync), + new object[] + { + SerializableSourceReferenceItem.Dehydrate(definitionItem, reference), + }, + CancellationToken).ConfigureAwait(false); + } + + #endregion + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/GlobalNotificationDelivery/RemoteGlobalNotificationDeliveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_GlobalNotifications.cs similarity index 52% rename from src/Workspaces/Remote/ServiceHub/Services/GlobalNotificationDelivery/RemoteGlobalNotificationDeliveryService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_GlobalNotifications.cs index c46db0ab9dccd..962126e2eaca3 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/GlobalNotificationDelivery/RemoteGlobalNotificationDeliveryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_GlobalNotifications.cs @@ -6,49 +6,35 @@ using System.Collections.Generic; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Remote.Services; namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteGlobalNotificationDeliveryService : BrokeredServiceBase, IRemoteGlobalNotificationDeliveryService + internal partial class CodeAnalysisService : ServiceBase, IRemoteGlobalNotificationDeliveryService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteGlobalNotificationDeliveryService CreateService(in ServiceConstructionArguments arguments) - => new RemoteGlobalNotificationDeliveryService(arguments); - } - - public RemoteGlobalNotificationDeliveryService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - /// /// Remote API. /// - public ValueTask OnGlobalOperationStartedAsync(CancellationToken cancellationToken) + public void OnGlobalOperationStarted() { - return RunServiceAsync(cancellationToken => + RunService(() => { var globalOperationNotificationService = GetGlobalOperationNotificationService(); globalOperationNotificationService?.OnStarted(); - return default; - }, cancellationToken); + }, CancellationToken.None); } /// /// Remote API. /// - public ValueTask OnGlobalOperationStoppedAsync(IReadOnlyList operations, bool cancelled, CancellationToken cancellationToken) + public void OnGlobalOperationStopped(IReadOnlyList operations, bool cancelled) { - return RunServiceAsync(cancellationToken => + RunService(() => { var globalOperationNotificationService = GetGlobalOperationNotificationService(); globalOperationNotificationService?.OnStopped(operations, cancelled); - return default; - }, cancellationToken); + }, CancellationToken.None); } private RemoteGlobalOperationNotificationService? GetGlobalOperationNotificationService() diff --git a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_NavigateTo.cs similarity index 59% rename from src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_NavigateTo.cs index 5d86eacbc63eb..911084e0b4277 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_NavigateTo.cs @@ -11,27 +11,12 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteNavigateToSearchService : BrokeredServiceBase, IRemoteNavigateToSearchService + internal partial class CodeAnalysisService : IRemoteNavigateToSearchService { - internal sealed class Factory : FactoryBase + public Task> SearchDocumentAsync( + PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, string[] kinds, CancellationToken cancellationToken) { - protected override IRemoteNavigateToSearchService CreateService(in ServiceConstructionArguments arguments) - => new RemoteNavigateToSearchService(arguments); - } - - public RemoteNavigateToSearchService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask> SearchDocumentAsync( - PinnedSolutionInfo solutionInfo, - DocumentId documentId, - string searchPattern, - ImmutableArray kinds, - CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -46,15 +31,10 @@ public ValueTask> SearchDocum }, cancellationToken); } - public ValueTask> SearchProjectAsync( - PinnedSolutionInfo solutionInfo, - ProjectId projectId, - ImmutableArray priorityDocumentIds, - string searchPattern, - ImmutableArray kinds, - CancellationToken cancellationToken) + public Task> SearchProjectAsync( + PinnedSolutionInfo solutionInfo, ProjectId projectId, DocumentId[] priorityDocumentIds, string searchPattern, string[] kinds, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -72,7 +52,7 @@ public ValueTask> SearchProje }, cancellationToken); } - private static ImmutableArray Convert( + private static IList Convert( ImmutableArray result) { return result.SelectAsArray(SerializableNavigateToSearchResult.Dehydrate); diff --git a/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Renamer.cs similarity index 77% rename from src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Renamer.cs index 6ed093388c51d..91e3284bde618 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_Renamer.cs @@ -13,28 +13,18 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteRenamerService : BrokeredServiceBase, IRemoteRenamerService + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteRenamer { - internal sealed class Factory : FactoryBase - { - protected override IRemoteRenamerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteRenamerService(arguments); - } - - public RemoteRenamerService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask RenameSymbolAsync( + public Task RenameSymbolAsync( PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbolAndProjectId, string newName, SerializableRenameOptionSet options, - ImmutableArray nonConflictSymbolIds, + SerializableSymbolAndProjectId[] nonConflictSymbolIds, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -56,13 +46,13 @@ public RemoteRenamerService(in ServiceConstructionArguments arguments) }, cancellationToken); } - public ValueTask FindRenameLocationsAsync( + public Task FindRenameLocationsAsync( PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbolAndProjectId, SerializableRenameOptionSet options, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -81,14 +71,14 @@ public RemoteRenamerService(in ServiceConstructionArguments arguments) }, cancellationToken); } - public ValueTask ResolveConflictsAsync( + public Task ResolveConflictsAsync( PinnedSolutionInfo solutionInfo, SerializableRenameLocations renameLocationSet, string replacementText, - ImmutableArray nonConflictSymbolIds, + SerializableSymbolAndProjectId[] nonConflictSymbolIds, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -109,12 +99,10 @@ public RemoteRenamerService(in ServiceConstructionArguments arguments) }, cancellationToken); } - private static async Task?> GetNonConflictSymbolsAsync(Solution solution, ImmutableArray nonConflictSymbolIds, CancellationToken cancellationToken) + private static async Task?> GetNonConflictSymbolsAsync(Solution solution, SerializableSymbolAndProjectId[]? nonConflictSymbolIds, CancellationToken cancellationToken) { - if (nonConflictSymbolIds.IsDefault) - { + if (nonConflictSymbolIds == null) return null; - } var builder = ImmutableHashSet.CreateBuilder(); foreach (var id in nonConflictSymbolIds) diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassification.cs similarity index 62% rename from src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassification.cs index 4997b5190348f..6f5edba308677 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassification.cs @@ -2,34 +2,21 @@ // 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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; -using Microsoft.ServiceHub.Framework; namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteSemanticClassificationService : BrokeredServiceBase, IRemoteSemanticClassificationService + internal partial class CodeAnalysisService : IRemoteSemanticClassificationService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSemanticClassificationService CreateService(in ServiceConstructionArguments arguments) - => new RemoteSemanticClassificationService(arguments); - } - - public RemoteSemanticClassificationService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask GetSemanticClassificationsAsync( + public Task GetSemanticClassificationsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassificationCache.cs similarity index 93% rename from src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassificationCache.cs index a5e119710ee40..e0dd94a55f170 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SemanticClassificationCache.cs @@ -4,7 +4,6 @@ #nullable enable -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -18,24 +17,12 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.ServiceHub.Framework; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteSemanticClassificationCacheService : BrokeredServiceBase, IRemoteSemanticClassificationCacheService + internal partial class CodeAnalysisService : IRemoteSemanticClassificationCacheService { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSemanticClassificationCacheService CreateService(in ServiceConstructionArguments arguments) - => new RemoteSemanticClassificationCacheService(arguments); - } - - public RemoteSemanticClassificationCacheService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - /// /// Key we use to look this up in the persistence store for a particular document. /// @@ -70,13 +57,13 @@ private static async Task GetChecksumAsync(Document document, Cancella return textChecksum; } - public ValueTask CacheSemanticClassificationsAsync( + public Task CacheSemanticClassificationsAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, bool isFullyLoaded, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { // Once fully loaded, we can clear any of the cached information we stored during load. if (isFullyLoaded) @@ -180,10 +167,10 @@ private static void WriteTo(List classifiedSpans, ObjectWriter w } } - public ValueTask GetCachedSemanticClassificationsAsync( + public Task GetCachedSemanticClassificationsAsync( SerializableDocumentKey documentKey, TextSpan textSpan, Checksum checksum, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { var classifiedSpans = await TryGetOrReadCachedSemanticClassificationsAsync( documentKey.Rehydrate(), checksum, cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SymbolFinder.cs similarity index 58% rename from src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SymbolFinder.cs index 94097cbd89237..b48c9310ccefa 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/CodeAnalysisService_SymbolFinder.cs @@ -15,30 +15,17 @@ namespace Microsoft.CodeAnalysis.Remote { - internal sealed class RemoteSymbolFinderService : BrokeredServiceBase, IRemoteSymbolFinderService + // root level service for all Roslyn services + internal partial class CodeAnalysisService : IRemoteSymbolFinder { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSymbolFinderService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteSymbolFinderService(arguments, callback); - } - - private readonly RemoteCallback _callback; - - public RemoteSymbolFinderService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask FindReferencesAsync( + public Task FindReferencesAsync( PinnedSolutionInfo solutionInfo, SerializableSymbolAndProjectId symbolAndProjectIdArg, - ImmutableArray documentArgs, - FindReferencesSearchOptions options, + DocumentId[] documentArgs, + SerializableFindReferencesSearchOptions options, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -47,7 +34,7 @@ public ValueTask FindReferencesAsync( var symbol = await symbolAndProjectIdArg.TryRehydrateAsync( solution, cancellationToken).ConfigureAwait(false); - var progressCallback = new FindReferencesProgressCallback(solution, _callback, cancellationToken); + var progressCallback = new FindReferencesProgressCallback(solution, EndPoint, cancellationToken); if (symbol == null) { @@ -60,26 +47,27 @@ public ValueTask FindReferencesAsync( // that are not all the same language and might not exist in the OOP process // (like the JS parts of a .cshtml file). Filter them out here. This will // need to be revisited if we someday support FAR between these languages. - var documents = documentArgs.IsDefault ? null : - documentArgs.Select(solution.GetDocument).WhereNotNull().ToImmutableHashSet(); + var documents = documentArgs?.Select(solution.GetDocument) + .WhereNotNull() + .ToImmutableHashSet(); await SymbolFinder.FindReferencesInCurrentProcessAsync( symbol, solution, progressCallback, - documents, options, cancellationToken).ConfigureAwait(false); + documents, options.Rehydrate(), cancellationToken).ConfigureAwait(false); } }, cancellationToken); } - public ValueTask FindLiteralReferencesAsync(PinnedSolutionInfo solutionInfo, object value, TypeCode typeCode, CancellationToken cancellationToken) + public Task FindLiteralReferencesAsync(PinnedSolutionInfo solutionInfo, object value, TypeCode typeCode, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { var convertedType = System.Convert.ChangeType(value, typeCode); var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var progressCallback = new FindLiteralReferencesProgressCallback(_callback, cancellationToken); + var progressCallback = new FindLiteralReferencesProgressCallback(EndPoint, cancellationToken); await SymbolFinder.FindLiteralReferencesInCurrentProcessAsync( convertedType, solution, progressCallback, cancellationToken).ConfigureAwait(false); } @@ -96,7 +84,7 @@ private static ImmutableArray Convert(ImmutableA return result.ToImmutable(); } - public ValueTask> FindAllDeclarationsWithNormalQueryAsync( + public Task> FindAllDeclarationsWithNormalQueryAsync( PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, @@ -104,7 +92,7 @@ public ValueTask> FindAllDeclarat SymbolFilter criteria, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -121,14 +109,14 @@ public ValueTask> FindAllDeclarat }, cancellationToken); } - public ValueTask> FindSolutionSourceDeclarationsWithNormalQueryAsync( + public Task> FindSolutionSourceDeclarationsWithNormalQueryAsync( PinnedSolutionInfo solutionInfo, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -141,7 +129,7 @@ public ValueTask> FindSolutionSou }, cancellationToken); } - public ValueTask> FindProjectSourceDeclarationsWithNormalQueryAsync( + public Task> FindProjectSourceDeclarationsWithNormalQueryAsync( PinnedSolutionInfo solutionInfo, ProjectId projectId, string name, @@ -149,7 +137,7 @@ public ValueTask> FindProjectSour SymbolFilter criteria, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -164,10 +152,10 @@ public ValueTask> FindProjectSour }, cancellationToken); } - public ValueTask> FindSolutionSourceDeclarationsWithPatternAsync( + public Task> FindSolutionSourceDeclarationsWithPatternAsync( PinnedSolutionInfo solutionInfo, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -181,10 +169,10 @@ public ValueTask> FindSolutionSou }, cancellationToken); } - public ValueTask> FindProjectSourceDeclarationsWithPatternAsync( + public Task> FindProjectSourceDeclarationsWithPatternAsync( PinnedSolutionInfo solutionInfo, ProjectId projectId, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) { - return RunServiceAsync(async cancellationToken => + return RunServiceAsync(async () => { using (UserOperationBooster.Boost()) { @@ -201,75 +189,76 @@ public ValueTask> FindProjectSour private sealed class FindLiteralReferencesProgressCallback : IStreamingFindLiteralReferencesProgress, IStreamingProgressTracker { - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; private readonly CancellationToken _cancellationToken; public IStreamingProgressTracker ProgressTracker { get; } - public FindLiteralReferencesProgressCallback(RemoteCallback callback, CancellationToken cancellationToken) + public FindLiteralReferencesProgressCallback(RemoteEndPoint endPoint, CancellationToken cancellationToken) { - _callback = callback; + _endPoint = endPoint; _cancellationToken = cancellationToken; ProgressTracker = this; } - public ValueTask OnReferenceFoundAsync(Document document, TextSpan span) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnLiteralReferenceFoundAsync(document.Id, span), _cancellationToken); + public Task OnReferenceFoundAsync(Document document, TextSpan span) + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindLiteralsServerCallback.OnReferenceFoundAsync), new object[] { document.Id, span }, _cancellationToken); - public ValueTask AddItemsAsync(int count) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddItemsAsync(count), _cancellationToken); + public Task AddItemsAsync(int count) + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindLiteralsServerCallback.AddItemsAsync), new object[] { count }, _cancellationToken); - public ValueTask ItemCompletedAsync() - => _callback.InvokeAsync((callback, cancellationToken) => callback.ItemCompletedAsync(), _cancellationToken); + public Task ItemCompletedAsync() + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindLiteralsServerCallback.ItemCompletedAsync), new object[] { }, _cancellationToken); } private sealed class FindReferencesProgressCallback : IStreamingFindReferencesProgress, IStreamingProgressTracker { private readonly Solution _solution; - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; private readonly CancellationToken _cancellationToken; public IStreamingProgressTracker ProgressTracker { get; } - public FindReferencesProgressCallback(Solution solution, RemoteCallback callback, CancellationToken cancellationToken) + public FindReferencesProgressCallback(Solution solution, RemoteEndPoint endPoint, CancellationToken cancellationToken) { _solution = solution; - _callback = callback; + _endPoint = endPoint; _cancellationToken = cancellationToken; ProgressTracker = this; } - public ValueTask OnStartedAsync() - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnStartedAsync(), _cancellationToken); + public Task OnStartedAsync() + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.OnStartedAsync), Array.Empty(), _cancellationToken); - public ValueTask OnCompletedAsync() - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnCompletedAsync(), _cancellationToken); + public Task OnCompletedAsync() + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.OnCompletedAsync), Array.Empty(), _cancellationToken); - public ValueTask OnFindInDocumentStartedAsync(Document document) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnFindInDocumentStartedAsync(document.Id), _cancellationToken); + public Task OnFindInDocumentStartedAsync(Document document) + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.OnFindInDocumentStartedAsync), new object[] { document.Id }, _cancellationToken); - public ValueTask OnFindInDocumentCompletedAsync(Document document) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnFindInDocumentCompletedAsync(document.Id), _cancellationToken); + public Task OnFindInDocumentCompletedAsync(Document document) + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.OnFindInDocumentCompletedAsync), new object[] { document.Id }, _cancellationToken); - public ValueTask OnDefinitionFoundAsync(ISymbol definition) - { - var dehydratedDefinition = SerializableSymbolAndProjectId.Dehydrate(_solution, definition, _cancellationToken); - return _callback.InvokeAsync((callback, cancellationToken) => callback.OnDefinitionFoundAsync(dehydratedDefinition), _cancellationToken); - } - - public ValueTask OnReferenceFoundAsync(ISymbol definition, ReferenceLocation reference) - { - var dehydratedDefinition = SerializableSymbolAndProjectId.Dehydrate(_solution, definition, _cancellationToken); - var dehydratedReference = SerializableReferenceLocation.Dehydrate(reference, _cancellationToken); + public Task OnDefinitionFoundAsync(ISymbol definition) + => _endPoint.InvokeAsync( + nameof(SymbolFinder.FindReferencesServerCallback.OnDefinitionFoundAsync), + new object[] { SerializableSymbolAndProjectId.Dehydrate(_solution, definition, _cancellationToken) }, _cancellationToken); - return _callback.InvokeAsync((callback, cancellationToken) => callback.OnReferenceFoundAsync(dehydratedDefinition, dehydratedReference), _cancellationToken); - } + public Task OnReferenceFoundAsync(ISymbol definition, ReferenceLocation reference) + => _endPoint.InvokeAsync( + nameof(SymbolFinder.FindReferencesServerCallback.OnReferenceFoundAsync), + new object[] + { + SerializableSymbolAndProjectId.Dehydrate(_solution, definition, _cancellationToken), + SerializableReferenceLocation.Dehydrate(reference, _cancellationToken), + }, + _cancellationToken); - public ValueTask AddItemsAsync(int count) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddItemsAsync(count), _cancellationToken); + public Task AddItemsAsync(int count) + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.AddItemsAsync), new object[] { count }, _cancellationToken); - public ValueTask ItemCompletedAsync() - => _callback.InvokeAsync((callback, cancellationToken) => callback.ItemCompletedAsync(), _cancellationToken); + public Task ItemCompletedAsync() + => _endPoint.InvokeAsync(nameof(SymbolFinder.FindReferencesServerCallback.ItemCompletedAsync), Array.Empty(), _cancellationToken); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/DiagnosticComputer.cs similarity index 81% rename from src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/DiagnosticComputer.cs index 9789ab33305e2..a92a030e50822 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/DiagnosticComputer.cs @@ -61,7 +61,7 @@ public DiagnosticComputer( _performanceTracker = project.IsFromPrimaryBranch() ? project.Solution.Workspace.Services.GetService() : null; } - public async Task GetDiagnosticsAsync( + public async Task> GetDiagnosticsAsync( IEnumerable analyzerIds, bool reportSuppressedDiagnostics, bool logPerformanceInfo, @@ -74,13 +74,12 @@ public async Task GetDiagnosticsAsync( var analyzers = GetAnalyzers(analyzerToIdMap, analyzerIds); if (analyzers.IsEmpty) { - return SerializableDiagnosticAnalysisResults.Empty; + return DiagnosticAnalysisResultMap.Empty; } var cacheService = _project.Solution.Workspace.Services.GetRequiredService(); using var cache = cacheService.EnableCaching(_project.Id); var skippedAnalyzersInfo = _project.GetSkippedAnalyzersInfo(_analyzerInfoCache); - try { return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, analyzers, skippedAnalyzersInfo, @@ -94,7 +93,7 @@ public async Task GetDiagnosticsAsync( } } - private async Task AnalyzeAsync( + private async Task> AnalyzeAsync( CompilationWithAnalyzers compilationWithAnalyzers, BidirectionalMap analyzerToIdMap, ImmutableArray analyzers, @@ -124,64 +123,43 @@ private async Task AnalyzeAsync( _project, VersionStamp.Default, compilationWithAnalyzers.Compilation, analyzers, skippedAnalyzersInfo, reportSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); + var result = builderMap.ToImmutableDictionary(kv => GetAnalyzerId(analyzerToIdMap, kv.Key), kv => kv.Value); var telemetry = getTelemetryInfo ? GetTelemetryInfo(analysisResult, analyzers, analyzerToIdMap) - : ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)>.Empty; - - return new SerializableDiagnosticAnalysisResults(Dehydrate(builderMap, analyzerToIdMap), telemetry); - } - - private static ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> Dehydrate( - ImmutableDictionary builderMap, - BidirectionalMap analyzerToIdMap) - { - using var _ = ArrayBuilder<(string analyzerId, SerializableDiagnosticMap diagnosticMap)>.GetInstance(out var diagnostics); - - foreach (var (analyzer, analyzerResults) in builderMap) - { - var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); - - diagnostics.Add((analyzerId, - new SerializableDiagnosticMap( - analyzerResults.SyntaxLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.SemanticLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.NonLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.Others))); - } - - return diagnostics.ToImmutable(); - } + : ImmutableDictionary.Empty; + return DiagnosticAnalysisResultMap.Create(result, telemetry); - private static ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)> GetTelemetryInfo( - AnalysisResult analysisResult, - ImmutableArray analyzers, - BidirectionalMap analyzerToIdMap) - { - Func shouldInclude; - if (analyzers.Length < analysisResult.AnalyzerTelemetryInfo.Count) + static ImmutableDictionary GetTelemetryInfo( + AnalysisResult analysisResult, + ImmutableArray analyzers, + BidirectionalMap analyzerToIdMap) { - // Filter the telemetry info to the executed analyzers. - using var _1 = PooledHashSet.GetInstance(out var analyzersSet); - analyzersSet.AddRange(analyzers); + Func shouldInclude; + if (analyzers.Length < analysisResult.AnalyzerTelemetryInfo.Count) + { + // Filter the telemetry info to the executed analyzers. + using var _ = PooledHashSet.GetInstance(out var analyzersSet); + analyzersSet.AddRange(analyzers); - shouldInclude = analyzer => analyzersSet.Contains(analyzer); - } - else - { - shouldInclude = _ => true; - } + shouldInclude = analyzer => analyzersSet.Contains(analyzer); + } + else + { + shouldInclude = _ => true; + } - using var _2 = ArrayBuilder<(string analyzerId, AnalyzerTelemetryInfo)>.GetInstance(out var telemetryBuilder); - foreach (var (analyzer, analyzerTelemetry) in analysisResult.AnalyzerTelemetryInfo) - { - if (shouldInclude(analyzer)) + var telemetryBuilder = ImmutableDictionary.CreateBuilder(); + foreach (var (analyzer, analyzerTelemetry) in analysisResult.AnalyzerTelemetryInfo) { - var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); - telemetryBuilder.Add((analyzerId, analyzerTelemetry)); + if (shouldInclude(analyzer)) + { + var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); + telemetryBuilder.Add(analyzerId, analyzerTelemetry); + } } - } - return telemetryBuilder.ToImmutable(); + return telemetryBuilder.ToImmutable(); + } } private static string GetAnalyzerId(BidirectionalMap analyzerMap, DiagnosticAnalyzer analyzer) diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/IPerformanceTrackerService.cs similarity index 100% rename from src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/IPerformanceTrackerService.cs diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/PerformanceQueue.cs similarity index 100% rename from src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/PerformanceQueue.cs diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/PerformanceTrackerService.cs similarity index 100% rename from src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs rename to src/Workspaces/Remote/ServiceHub/Services/CodeAnalysis/Diagnostics/PerformanceTrackerService.cs diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs deleted file mode 100644 index 2b074d0bfe9a8..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs +++ /dev/null @@ -1,122 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeLens; -using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteCodeLensReferencesService : BrokeredServiceBase, IRemoteCodeLensReferencesService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteCodeLensReferencesService CreateService(in ServiceConstructionArguments arguments) - => new RemoteCodeLensReferencesService(arguments); - } - - public RemoteCodeLensReferencesService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - private static async ValueTask TryFindNodeAsync(Solution solution, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - var document = solution.GetDocument(documentId); - if (document == null) - { - return null; - } - - var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - return syntaxRoot.FindNode(textSpan); - } - - public ValueTask GetReferenceCountAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetReferenceCountAsync, documentId.ProjectId.DebugName, cancellationToken)) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } - - return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync( - solution, - documentId, - syntaxNode, - maxResultCount, - cancellationToken).ConfigureAwait(false); - } - }, cancellationToken); - } - - public ValueTask?> FindReferenceLocationsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceLocationsAsync, documentId.ProjectId.DebugName, cancellationToken)) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } - - return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync( - solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); - } - }, cancellationToken); - } - - public ValueTask?> FindReferenceMethodsAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceMethodsAsync, documentId.ProjectId.DebugName, cancellationToken)) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } - - return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync( - solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); - } - }, cancellationToken); - } - - public ValueTask GetFullyQualifiedNameAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetFullyQualifiedName, documentId.ProjectId.DebugName, cancellationToken)) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } - - return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedNameAsync( - solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); - } - }, cancellationToken); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs deleted file mode 100644 index 04b9d7636f733..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs +++ /dev/null @@ -1,60 +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.Collections.Immutable; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteDependentTypeFinderService : BrokeredServiceBase, IRemoteDependentTypeFinderService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDependentTypeFinderService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDependentTypeFinderService(arguments); - } - - public RemoteDependentTypeFinderService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask> FindTypesAsync( - PinnedSolutionInfo solutionInfo, - SerializableSymbolAndProjectId typeAndProjectId, - ImmutableArray projectIdsOpt, - bool transitive, - DependentTypesKind kind, - CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (UserOperationBooster.Boost()) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - - var symbol = await typeAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); - - if (symbol is not INamedTypeSymbol namedType) - return ImmutableArray.Empty; - - var projects = projectIdsOpt.IsDefault ? null : projectIdsOpt.Select(id => solution.GetRequiredProject(id)).ToImmutableHashSet(); - - var types = await DependentTypeFinder.FindTypesInCurrentProcessAsync(namedType, solution, projects, transitive, kind, cancellationToken).ConfigureAwait(false); - - return types.SelectAsArray( - t => SerializableSymbolAndProjectId.Dehydrate(solution, t, cancellationToken)); - } - }, cancellationToken); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs new file mode 100644 index 0000000000000..f98a5fde47d91 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzer.cs @@ -0,0 +1,43 @@ +// 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.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.DesignerAttribute; + +namespace Microsoft.CodeAnalysis.Remote +{ + internal sealed class RemoteDesignerAttributeIncrementalAnalyzer : AbstractDesignerAttributeIncrementalAnalyzer + { + /// + /// Channel back to VS to inform it of the designer attributes we discover. + /// + private readonly RemoteEndPoint _endPoint; + + public RemoteDesignerAttributeIncrementalAnalyzer(Workspace workspace, RemoteEndPoint endPoint) + : base(workspace) + { + _endPoint = endPoint; + } + + protected override Task ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) + { + return _endPoint.InvokeAsync( + nameof(IDesignerAttributeListener.OnProjectRemovedAsync), + new object[] { projectId }, + cancellationToken); + } + + protected override Task ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken) + { + return _endPoint.InvokeAsync( + nameof(IDesignerAttributeListener.ReportDesignerAttributeDataAsync), + new object[] { data }, + cancellationToken); + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs similarity index 81% rename from src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs rename to src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs index a20b96d5c77ea..b64be61337b1a 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeIncrementalAnalyzerProvider.cs @@ -4,7 +4,6 @@ #nullable enable -using Microsoft.CodeAnalysis.DesignerAttribute; using Microsoft.CodeAnalysis.SolutionCrawler; namespace Microsoft.CodeAnalysis.Remote @@ -16,14 +15,14 @@ namespace Microsoft.CodeAnalysis.Remote /// internal sealed class RemoteDesignerAttributeIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider { - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; - public RemoteDesignerAttributeIncrementalAnalyzerProvider(RemoteCallback callback) + public RemoteDesignerAttributeIncrementalAnalyzerProvider(RemoteEndPoint endPoint) { - _callback = callback; + _endPoint = endPoint; } public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new RemoteDesignerAttributeIncrementalAnalyzer(workspace, _callback); + => new RemoteDesignerAttributeIncrementalAnalyzer(workspace, _endPoint); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeService.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeService.cs new file mode 100644 index 0000000000000..493281e2b4d7b --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttribute/RemoteDesignerAttributeService.cs @@ -0,0 +1,43 @@ +// 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.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.DesignerAttribute; +using Microsoft.CodeAnalysis.SolutionCrawler; + +namespace Microsoft.CodeAnalysis.Remote +{ + internal sealed class RemoteDesignerAttributeService : ServiceBase, IRemoteDesignerAttributeService + { + public RemoteDesignerAttributeService( + Stream stream, IServiceProvider serviceProvider) + : base(serviceProvider, stream) + { + StartService(); + } + + public Task StartScanningForDesignerAttributesAsync(CancellationToken cancellation) + { + return RunServiceAsync(() => + { + var registrationService = GetWorkspace().Services.GetRequiredService(); + var analyzerProvider = new RemoteDesignerAttributeIncrementalAnalyzerProvider(this.EndPoint); + + registrationService.AddAnalyzerProvider( + analyzerProvider, + new IncrementalAnalyzerProviderMetadata( + nameof(RemoteDesignerAttributeIncrementalAnalyzerProvider), + highPriorityForActiveFile: false, + workspaceKinds: WorkspaceKind.RemoteWorkspace)); + + return Task.CompletedTask; + }, cancellation); + } + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeDiscoveryService.cs deleted file mode 100644 index 7f82046e5801c..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeDiscoveryService.cs +++ /dev/null @@ -1,48 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.DesignerAttribute; -using Microsoft.CodeAnalysis.SolutionCrawler; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteDesignerAttributeDiscoveryService : BrokeredServiceBase, IRemoteDesignerAttributeDiscoveryService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDesignerAttributeDiscoveryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteDesignerAttributeDiscoveryService(arguments, callback); - } - - private readonly RemoteCallback _callback; - - public RemoteDesignerAttributeDiscoveryService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask StartScanningForDesignerAttributesAsync(CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - { - var registrationService = GetWorkspace().Services.GetRequiredService(); - var analyzerProvider = new RemoteDesignerAttributeIncrementalAnalyzerProvider(_callback); - - registrationService.AddAnalyzerProvider( - analyzerProvider, - new IncrementalAnalyzerProviderMetadata( - nameof(RemoteDesignerAttributeIncrementalAnalyzerProvider), - highPriorityForActiveFile: false, - workspaceKinds: WorkspaceKind.RemoteWorkspace)); - - return default; - }, cancellationToken); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzer.cs deleted file mode 100644 index 1d316962cbdd9..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/DesignerAttributeDiscovery/RemoteDesignerAttributeIncrementalAnalyzer.cs +++ /dev/null @@ -1,42 +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.Generic; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.DesignerAttribute; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteDesignerAttributeIncrementalAnalyzer : AbstractDesignerAttributeIncrementalAnalyzer - { - /// - /// Channel back to VS to inform it of the designer attributes we discover. - /// - private readonly RemoteCallback _callback; - - public RemoteDesignerAttributeIncrementalAnalyzer(Workspace workspace, RemoteCallback callback) - : base(workspace) - { - _callback = callback; - } - - protected override async ValueTask ReportProjectRemovedAsync(ProjectId projectId, CancellationToken cancellationToken) - { - await _callback.InvokeAsync( - (callback, cancellationToken) => callback.OnProjectRemovedAsync(projectId, cancellationToken), - cancellationToken).ConfigureAwait(false); - } - - protected override async ValueTask ReportDesignerAttributeDataAsync(List data, CancellationToken cancellationToken) - { - await _callback.InvokeAsync( - (callback, cancellationToken) => callback.ReportDesignerAttributeDataAsync(data.ToImmutableArray(), cancellationToken), - cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs b/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs deleted file mode 100644 index 1290119034611..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs +++ /dev/null @@ -1,150 +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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.FindUsages; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.Shared.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteFindUsagesService : BrokeredServiceBase, IRemoteFindUsagesService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteFindUsagesService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteFindUsagesService(arguments, callback); - } - - private readonly RemoteCallback _callback; - - public RemoteFindUsagesService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask FindReferencesAsync( - PinnedSolutionInfo solutionInfo, - SerializableSymbolAndProjectId symbolAndProjectId, - FindReferencesSearchOptions options, - CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (UserOperationBooster.Boost()) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var project = solution.GetProject(symbolAndProjectId.ProjectId); - - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); - - if (symbol == null) - return; - - var context = new RemoteFindUsageContext(_callback, cancellationToken); - await AbstractFindUsagesService.FindReferencesAsync( - context, symbol, project, options).ConfigureAwait(false); - } - }, cancellationToken); - } - - public ValueTask FindImplementationsAsync( - PinnedSolutionInfo solutionInfo, - SerializableSymbolAndProjectId symbolAndProjectId, - CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (UserOperationBooster.Boost()) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var project = solution.GetProject(symbolAndProjectId.ProjectId); - - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); - if (symbol == null) - return; - - var context = new RemoteFindUsageContext(_callback, cancellationToken); - await AbstractFindUsagesService.FindImplementationsAsync( - symbol, project, context).ConfigureAwait(false); - } - }, cancellationToken); - } - - private sealed class RemoteFindUsageContext : IFindUsagesContext, IStreamingProgressTracker - { - private readonly RemoteCallback _callback; - private readonly Dictionary _definitionItemToId = new Dictionary(); - - public CancellationToken CancellationToken { get; } - - public RemoteFindUsageContext(RemoteCallback callback, CancellationToken cancellationToken) - { - _callback = callback; - CancellationToken = cancellationToken; - } - - #region IStreamingProgressTracker - - public ValueTask AddItemsAsync(int count) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddItemsAsync(count), CancellationToken); - - public ValueTask ItemCompletedAsync() - => _callback.InvokeAsync((callback, cancellationToken) => callback.ItemCompletedAsync(), CancellationToken); - - #endregion - - #region IFindUsagesContext - - public IStreamingProgressTracker ProgressTracker => this; - - public ValueTask ReportMessageAsync(string message) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportMessageAsync(message), CancellationToken); - - [Obsolete] - public ValueTask ReportProgressAsync(int current, int maximum) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportProgressAsync(current, maximum), CancellationToken); - - public ValueTask SetSearchTitleAsync(string title) - => _callback.InvokeAsync((callback, cancellationToken) => callback.SetSearchTitleAsync(title), CancellationToken); - - public ValueTask OnDefinitionFoundAsync(DefinitionItem definition) - { - var id = GetOrAddDefinitionItemId(definition); - var dehydratedDefinition = SerializableDefinitionItem.Dehydrate(id, definition); - return _callback.InvokeAsync((callback, cancellationToken) => callback.OnDefinitionFoundAsync(dehydratedDefinition), CancellationToken); - } - - private int GetOrAddDefinitionItemId(DefinitionItem item) - { - lock (_definitionItemToId) - { - if (!_definitionItemToId.TryGetValue(item, out var id)) - { - id = _definitionItemToId.Count; - _definitionItemToId.Add(item, id); - } - - return id; - } - } - - public ValueTask OnReferenceFoundAsync(SourceReferenceItem reference) - { - var definitionItem = GetOrAddDefinitionItemId(reference.Definition); - var dehydratedReference = SerializableSourceReferenceItem.Dehydrate(definitionItem, reference); - return _callback.InvokeAsync((callback, cancellationToken) => callback.OnReferenceFoundAsync(dehydratedReference), CancellationToken); - } - - #endregion - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.PerformanceReporter.cs b/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.PerformanceReporter.cs index 0c09f2234809b..e79f348454dd8 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.PerformanceReporter.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.PerformanceReporter.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Remote { - internal partial class RemoteHostService + internal partial class RemoteHostService : ServiceBase, IRemoteHostService { /// /// Track when last time report has sent and send new report if there is update after given internal diff --git a/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.cs b/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.cs index 31c5a8cfab3ff..7577d7cd826bd 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/Host/RemoteHostService.cs @@ -94,7 +94,7 @@ public void InitializeGlobalState(int uiCultureLCID, int cultureLCID, Cancellati /// /// Remote API. Initializes ServiceHub process global state. /// - public void InitializeTelemetrySession(int hostProcessId, string serializedSession, CancellationToken cancellationToken) + public void InitializeTelemetrySession(string host, string serializedSession, CancellationToken cancellationToken) { RunService(() => { @@ -110,7 +110,7 @@ public void InitializeTelemetrySession(int hostProcessId, string serializedSessi // log telemetry that service hub started RoslynLogger.Log(FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create(m => { - m["Host"] = hostProcessId; + m["Host"] = host; m["InstanceId"] = InstanceId; })); @@ -124,9 +124,9 @@ public void InitializeTelemetrySession(int hostProcessId, string serializedSessi }, cancellationToken); } - async ValueTask> IAssetSource.GetAssetsAsync(int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) + Task> IAssetSource.GetAssetsAsync(int scopeId, ISet checksums, ISerializerService serializerService, CancellationToken cancellationToken) { - return await RunServiceAsync(() => + return RunServiceAsync(() => { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_GetAssetsAsync, (serviceId, checksums) => $"{serviceId} - {Checksum.GetChecksumsLogInfo(checksums)}", scopeId, checksums, cancellationToken)) { @@ -136,13 +136,13 @@ public void InitializeTelemetrySession(int hostProcessId, string serializedSessi (stream, cancellationToken) => Task.FromResult(RemoteHostAssetSerialization.ReadData(stream, scopeId, checksums, serializerService, cancellationToken)), cancellationToken); } - }, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } // TODO: remove (https://github.com/dotnet/roslyn/issues/43477) - async ValueTask IAssetSource.IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) + Task IAssetSource.IsExperimentEnabledAsync(string experimentName, CancellationToken cancellationToken) { - return await RunServiceAsync(() => + return RunServiceAsync(() => { using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_IsExperimentEnabledAsync, experimentName, cancellationToken)) { @@ -151,7 +151,7 @@ async ValueTask IAssetSource.IsExperimentEnabledAsync(string experimentNam new object[] { experimentName }, cancellationToken); } - }, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } /// diff --git a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs deleted file mode 100644 index 40812914f3741..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs +++ /dev/null @@ -1,86 +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.AddImport; -using Microsoft.CodeAnalysis.Packaging; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SymbolSearch; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteMissingImportDiscoveryService : BrokeredServiceBase, IRemoteMissingImportDiscoveryService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteMissingImportDiscoveryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteMissingImportDiscoveryService(arguments, callback); - } - - private readonly RemoteCallback _callback; - - public RemoteMissingImportDiscoveryService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask> GetFixesAsync( - PinnedSolutionInfo solutionInfo, DocumentId documentId, TextSpan span, string diagnosticId, int maxResults, bool placeSystemNamespaceFirst, - bool searchReferenceAssemblies, ImmutableArray packageSources, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (UserOperationBooster.Boost()) - { - var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var document = solution.GetDocument(documentId); - - var service = document.GetLanguageService(); - - var symbolSearchService = new SymbolSearchService(_callback); - - var result = await service.GetFixesAsync( - document, span, diagnosticId, maxResults, placeSystemNamespaceFirst, - symbolSearchService, searchReferenceAssemblies, - packageSources, cancellationToken).ConfigureAwait(false); - - return result; - } - }, cancellationToken); - } - - /// - /// Provides an implementation of the on the remote side so that - /// Add-Import can find results in nuget packages/reference assemblies. This works - /// by remoting *from* the OOP server back to the host, which can then forward this - /// appropriately to wherever the real is running. This is necessary - /// because it's not guaranteed that the real will be running in - /// the same process that is supplying the . - /// - /// Ideally we would not need to bounce back to the host for this. - /// - private sealed class SymbolSearchService : ISymbolSearchService - { - private readonly RemoteCallback _callback; - - public SymbolSearchService(RemoteCallback callback) - { - _callback = callback; - } - - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), cancellationToken); - - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), cancellationToken); - - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), cancellationToken); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs index 84a79aee04856..08a28348e07a6 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzer.cs @@ -17,13 +17,13 @@ internal class RemoteProjectTelemetryIncrementalAnalyzer : IncrementalAnalyzerBa /// /// Channel back to VS to inform it of the designer attributes we discover. /// - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; private readonly object _gate = new object(); private readonly Dictionary _projectToData = new Dictionary(); - public RemoteProjectTelemetryIncrementalAnalyzer(RemoteCallback callback) - => _callback = callback; + public RemoteProjectTelemetryIncrementalAnalyzer(RemoteEndPoint endPoint) + => _endPoint = endPoint; /// /// Collects data from and reports it to the telemetry service. @@ -45,14 +45,16 @@ public override async Task AnalyzeProjectAsync(Project project, bool semanticsCh var documentsCount = project.DocumentIds.Count; var additionalDocumentsCount = project.AdditionalDocumentIds.Count; - var info = new ProjectTelemetryData( - projectId: projectId, - language: language, - analyzerReferencesCount: analyzerReferencesCount, - projectReferencesCount: projectReferencesCount, - metadataReferencesCount: metadataReferencesCount, - documentsCount: documentsCount, - additionalDocumentsCount: additionalDocumentsCount); + var info = new ProjectTelemetryData + { + ProjectId = projectId, + Language = language, + AnalyzerReferencesCount = analyzerReferencesCount, + ProjectReferencesCount = projectReferencesCount, + MetadataReferencesCount = metadataReferencesCount, + DocumentsCount = documentsCount, + AdditionalDocumentsCount = additionalDocumentsCount, + }; lock (_gate) { @@ -66,8 +68,9 @@ public override async Task AnalyzeProjectAsync(Project project, bool semanticsCh _projectToData[projectId] = info; } - await _callback.InvokeAsync( - (callback, cancellationToken) => callback.ReportProjectTelemetryDataAsync(info, cancellationToken), + await _endPoint.InvokeAsync( + nameof(IProjectTelemetryListener.ReportProjectTelemetryDataAsync), + new object[] { info }, cancellationToken).ConfigureAwait(false); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs index aad1c69e8c0e2..6af5bfe3de007 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryIncrementalAnalyzerProvider.cs @@ -4,7 +4,6 @@ #nullable enable -using Microsoft.CodeAnalysis.ProjectTelemetry; using Microsoft.CodeAnalysis.SolutionCrawler; namespace Microsoft.CodeAnalysis.Remote @@ -16,14 +15,14 @@ namespace Microsoft.CodeAnalysis.Remote /// internal class RemoteProjectTelemetryIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider { - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; - public RemoteProjectTelemetryIncrementalAnalyzerProvider(RemoteCallback callback) + public RemoteProjectTelemetryIncrementalAnalyzerProvider(RemoteEndPoint endPoint) { - _callback = callback; + _endPoint = endPoint; } public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new RemoteProjectTelemetryIncrementalAnalyzer(_callback); + => new RemoteProjectTelemetryIncrementalAnalyzer(_endPoint); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs index b40eca22e2fbc..5ce459e9292b9 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProjectTelemetry/RemoteProjectTelemetryService.cs @@ -10,33 +10,26 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ProjectTelemetry; using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.ServiceHub.Framework; namespace Microsoft.CodeAnalysis.Remote { - internal partial class RemoteProjectTelemetryService : BrokeredServiceBase, IRemoteProjectTelemetryService + internal partial class RemoteProjectTelemetryService : ServiceBase, IRemoteProjectTelemetryService { - internal sealed class Factory : FactoryBase + public RemoteProjectTelemetryService( + Stream stream, IServiceProvider serviceProvider) + : base(serviceProvider, stream) { - protected override IRemoteProjectTelemetryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteProjectTelemetryService(arguments, callback); + StartService(); } - private readonly RemoteCallback _callback; - - public RemoteProjectTelemetryService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask ComputeProjectTelemetryAsync(CancellationToken cancellationToken) + public Task ComputeProjectTelemetryAsync(CancellationToken cancellation) { - return RunServiceAsync(cancellationToken => + return RunServiceAsync(() => { var workspace = GetWorkspace(); + var endpoint = this.EndPoint; var registrationService = workspace.Services.GetRequiredService(); - var analyzerProvider = new RemoteProjectTelemetryIncrementalAnalyzerProvider(_callback); + var analyzerProvider = new RemoteProjectTelemetryIncrementalAnalyzerProvider(endpoint); registrationService.AddAnalyzerProvider( analyzerProvider, @@ -45,8 +38,8 @@ public ValueTask ComputeProjectTelemetryAsync(CancellationToken cancellationToke highPriorityForActiveFile: false, workspaceKinds: WorkspaceKind.RemoteWorkspace)); - return default; - }, cancellationToken); + return Task.CompletedTask; + }, cancellation); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs deleted file mode 100644 index c5e035dd80867..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs +++ /dev/null @@ -1,73 +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.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.SymbolSearch; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal sealed class RemoteSymbolSearchUpdateService : BrokeredServiceBase, IRemoteSymbolSearchUpdateService - { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSymbolSearchUpdateService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteSymbolSearchUpdateService(arguments, callback); - } - - private sealed class LogService : ISymbolSearchLogService - { - private readonly RemoteCallback _callback; - - public LogService(RemoteCallback callback) - => _callback = callback; - - public ValueTask LogExceptionAsync(string exception, string text, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.LogExceptionAsync(exception, text, cancellationToken), cancellationToken); - - public ValueTask LogInfoAsync(string text, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.LogInfoAsync(text, cancellationToken), cancellationToken); - } - - private readonly ISymbolSearchUpdateEngine _updateEngine; - - public RemoteSymbolSearchUpdateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _updateEngine = SymbolSearchUpdateEngineFactory.CreateEngineInProcess(new LogService(callback)); - } - - public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken), - cancellationToken); - } - - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), - cancellationToken); - } - - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - { - return RunServiceAsync(cancallationToken => - _updateEngine.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), - cancellationToken); - } - - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - { - return RunServiceAsync(cancallationToken => - _updateEngine.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), - cancellationToken); - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdateEngine/RemoteSymbolSearchUpdateEngine.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdateEngine/RemoteSymbolSearchUpdateEngine.cs new file mode 100644 index 0000000000000..4b9c0b2718b27 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdateEngine/RemoteSymbolSearchUpdateEngine.cs @@ -0,0 +1,93 @@ +// 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.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.SymbolSearch; + +namespace Microsoft.CodeAnalysis.Remote +{ + internal partial class RemoteSymbolSearchUpdateEngine : ServiceBase, IRemoteSymbolSearchUpdateEngine, ISymbolSearchLogService + { + private readonly ISymbolSearchUpdateEngine _updateEngine; + + public RemoteSymbolSearchUpdateEngine( + Stream stream, IServiceProvider serviceProvider) + : base(serviceProvider, stream) + { + _updateEngine = SymbolSearchUpdateEngineFactory.CreateEngineInProcess(logService: this); + + StartService(); + } + + public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory) + { + return RunServiceAsync(() => + { + // In non-test scenarios, we're not cancellable. Our lifetime will simply be that + // of the OOP process itself. i.e. when it goes away, it will just tear down our + // update-loop itself. So we don't need any additional controls over it. + return _updateEngine.UpdateContinuouslyAsync(sourceName, localSettingsDirectory); + }, CancellationToken.None); + } + + public Task> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + var results = await _updateEngine.FindPackagesWithTypeAsync( + source, name, arity, cancellationToken).ConfigureAwait(false); + + return (IList)results; + }, cancellationToken); + } + + public Task> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + var results = await _updateEngine.FindPackagesWithAssemblyAsync( + source, assemblyName, cancellationToken).ConfigureAwait(false); + + return (IList)results; + }, cancellationToken); + } + + public Task> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) + { + return RunServiceAsync(async () => + { + var results = await _updateEngine.FindReferenceAssembliesWithTypeAsync( + name, arity, cancellationToken).ConfigureAwait(false); + + return (IList)results; + }, cancellationToken); + } + + #region Messages to forward from here to VS + + public Task LogExceptionAsync(string exception, string text) + => EndPoint.InvokeAsync(nameof(LogExceptionAsync), new object[] { exception, text }, CancellationToken.None); + + public Task LogInfoAsync(string text) + => EndPoint.InvokeAsync(nameof(LogInfoAsync), new object[] { text }, CancellationToken.None); + + public Task OnDownloadFullDatabaseStartedAsync(string title) + => EndPoint.InvokeAsync(nameof(OnDownloadFullDatabaseStartedAsync), new object[] { title }, CancellationToken.None); + + public Task OnDownloadFullDatabaseSucceededAsync() + => EndPoint.InvokeAsync(nameof(OnDownloadFullDatabaseSucceededAsync), Array.Empty(), CancellationToken.None); + + public Task OnDownloadFullDatabaseCanceledAsync() + => EndPoint.InvokeAsync(nameof(OnDownloadFullDatabaseCanceledAsync), Array.Empty(), CancellationToken.None); + + public Task OnDownloadFullDatabaseFailedAsync(string message) + => EndPoint.InvokeAsync(nameof(OnDownloadFullDatabaseFailedAsync), new object[] { message }, CancellationToken.None); + + #endregion + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs similarity index 52% rename from src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzer.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs index b4e390d1dd20f..3b5caf13be6b6 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs @@ -16,16 +16,17 @@ internal sealed class RemoteTodoCommentsIncrementalAnalyzer : AbstractTodoCommen /// /// Channel back to VS to inform it of the designer attributes we discover. /// - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; - public RemoteTodoCommentsIncrementalAnalyzer(RemoteCallback callback) - => _callback = callback; + public RemoteTodoCommentsIncrementalAnalyzer(RemoteEndPoint endPoint) + => _endPoint = endPoint; - protected override async ValueTask ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) + protected override Task ReportTodoCommentDataAsync(DocumentId documentId, ImmutableArray data, CancellationToken cancellationToken) { - await _callback.InvokeAsync( - (callback, cancellationToken) => callback.ReportTodoCommentDataAsync(documentId, data, cancellationToken), - cancellationToken).ConfigureAwait(false); + return _endPoint.InvokeAsync( + nameof(ITodoCommentsListener.ReportTodoCommentDataAsync), + new object[] { documentId, data }, + cancellationToken); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzerProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs similarity index 75% rename from src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzerProvider.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs index fd1b99663ed4c..c75616fb64c01 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsIncrementalAnalyzerProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs @@ -5,8 +5,6 @@ #nullable enable using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.CodeAnalysis.TodoComments; -using Microsoft.ServiceHub.Framework; namespace Microsoft.CodeAnalysis.Remote { @@ -17,14 +15,14 @@ namespace Microsoft.CodeAnalysis.Remote /// internal sealed class RemoteTodoCommentsIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider { - private readonly RemoteCallback _callback; + private readonly RemoteEndPoint _endPoint; - public RemoteTodoCommentsIncrementalAnalyzerProvider(RemoteCallback callback) + public RemoteTodoCommentsIncrementalAnalyzerProvider(RemoteEndPoint endPoint) { - _callback = callback; + _endPoint = endPoint; } public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new RemoteTodoCommentsIncrementalAnalyzer(_callback); + => new RemoteTodoCommentsIncrementalAnalyzer(_endPoint); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs similarity index 51% rename from src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsDiscoveryService.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs index ee1e1beb0cae8..f1fe97ba4a1fc 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoCommentsDiscovery/RemoteTodoCommentsDiscoveryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs @@ -4,6 +4,8 @@ #nullable enable +using System; +using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.SolutionCrawler; @@ -11,29 +13,23 @@ namespace Microsoft.CodeAnalysis.Remote { - internal partial class RemoteTodoCommentsDiscoveryService : BrokeredServiceBase, IRemoteTodoCommentsDiscoveryService + internal partial class RemoteTodoCommentsService : ServiceBase, IRemoteTodoCommentsService { - internal sealed class Factory : FactoryBase + public RemoteTodoCommentsService( + Stream stream, IServiceProvider serviceProvider) + : base(serviceProvider, stream) { - protected override IRemoteTodoCommentsDiscoveryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteTodoCommentsDiscoveryService(arguments, callback); + StartService(); } - private readonly RemoteCallback _callback; - - public RemoteTodoCommentsDiscoveryService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } - - public ValueTask ComputeTodoCommentsAsync(CancellationToken cancellationToken) + public Task ComputeTodoCommentsAsync(CancellationToken cancellation) { - return RunServiceAsync(cancellationToken => + return RunServiceAsync(() => { var workspace = GetWorkspace(); + var endpoint = this.EndPoint; var registrationService = workspace.Services.GetRequiredService(); - var analyzerProvider = new RemoteTodoCommentsIncrementalAnalyzerProvider(_callback); + var analyzerProvider = new RemoteTodoCommentsIncrementalAnalyzerProvider(endpoint); registrationService.AddAnalyzerProvider( analyzerProvider, @@ -42,8 +38,8 @@ public ValueTask ComputeTodoCommentsAsync(CancellationToken cancellationToken) highPriorityForActiveFile: false, workspaceKinds: WorkspaceKind.RemoteWorkspace)); - return default; - }, cancellationToken); + return Task.CompletedTask; + }, cancellation); } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolUsageInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolUsageInfo.cs index af8f764eecbd3..73fe9fe4fc435 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolUsageInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolUsageInfo.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; -using System.Runtime.Serialization; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis @@ -14,19 +13,14 @@ namespace Microsoft.CodeAnalysis /// For namespaces and types, this corresponds to values from . /// For methods, fields, properties, events, locals and parameters, this corresponds to values from . /// - [DataContract] internal readonly struct SymbolUsageInfo : IEquatable { public static readonly SymbolUsageInfo None = Create(ValueUsageInfo.None); - [DataMember(Order = 0)] public ValueUsageInfo? ValueUsageInfoOpt { get; } - - [DataMember(Order = 1)] public TypeOrNamespaceUsageInfo? TypeOrNamespaceUsageInfoOpt { get; } - // Must be public since it's used for deserialization. - public SymbolUsageInfo(ValueUsageInfo? valueUsageInfoOpt, TypeOrNamespaceUsageInfo? typeOrNamespaceUsageInfoOpt) + private SymbolUsageInfo(ValueUsageInfo? valueUsageInfoOpt, TypeOrNamespaceUsageInfo? typeOrNamespaceUsageInfoOpt) { Debug.Assert(valueUsageInfoOpt.HasValue ^ typeOrNamespaceUsageInfoOpt.HasValue);