diff --git a/eng/targets/Services.props b/eng/targets/Services.props index c9b59f0c095bf..2efb19403388c 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -16,6 +16,7 @@ + diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 23e336b5d331e..ccc26beffe588 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -1296,6 +1296,9 @@ internal static bool SequenceEqual(this ImmutableArray internal static int IndexOf(this ImmutableArray array, T item, IEqualityComparer comparer) => array.IndexOf(item, startIndex: 0, comparer); + internal static bool IsSorted(this ImmutableArray array, Comparison comparison) + => IsSorted(array, Comparer.Create(comparison)); + internal static bool IsSorted(this ImmutableArray array, IComparer? comparer = null) { comparer ??= Comparer.Default; diff --git a/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs b/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs new file mode 100644 index 0000000000000..36da95ece96a7 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Copilot/CopilotWpfTextCreationListener.cs @@ -0,0 +1,135 @@ +// 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.ComponentModel.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Threading; +using Microsoft.VisualStudio.Language.Proposals; +using Microsoft.VisualStudio.Language.Suggestions; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Copilot; + +[Export(typeof(IWpfTextViewCreationListener))] +[ContentType(ContentTypeNames.RoslynContentType)] +[TextViewRole(PredefinedTextViewRoles.Document)] +internal sealed class CopilotWpfTextViewCreationListener : IWpfTextViewCreationListener +{ + private readonly IThreadingContext _threadingContext; + private readonly Lazy _suggestionServiceBase; + private readonly IAsynchronousOperationListener _listener; + + private readonly AsyncBatchingWorkQueue _workQueue; + + private int _started; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CopilotWpfTextViewCreationListener( + IThreadingContext threadingContext, + Lazy suggestionServiceBase, + IAsynchronousOperationListenerProvider listenerProvider) + { + _threadingContext = threadingContext; + _suggestionServiceBase = suggestionServiceBase; + _listener = listenerProvider.GetListener(FeatureAttribute.CopilotChangeAnalysis); + _workQueue = new AsyncBatchingWorkQueue( + DelayTimeSpan.Idle, + ProcessEventsAsync, + _listener, + _threadingContext.DisposalToken); + } + + public void TextViewCreated(IWpfTextView textView) + { + // On the first roslyn text view created, kick off work to hydrate the suggestion service and register to events + // from it. + if (Interlocked.CompareExchange(ref _started, 1, 0) == 0) + { + var token = _listener.BeginAsyncOperation(nameof(TextViewCreated)); + Task.Run(() => + { + var suggestionService = _suggestionServiceBase.Value; + suggestionService.SuggestionAccepted += OnSuggestionAccepted; + }).CompletesAsyncOperation(token); + } + } + + private void OnSuggestionAccepted(object sender, SuggestionAcceptedEventArgs e) + { + if (e.FinalProposal.Edits.Count == 0) + return; + + _workQueue.AddWork(e); + } + + private async ValueTask ProcessEventsAsync( + ImmutableSegmentedList list, CancellationToken cancellationToken) + { + foreach (var eventArgs in list) + await ProcessEventAsync(eventArgs, cancellationToken).ConfigureAwait(false); + } + + private static async ValueTask ProcessEventAsync( + SuggestionAcceptedEventArgs eventArgs, CancellationToken cancellationToken) + { + var proposal = eventArgs.FinalProposal; + var proposalId = proposal.ProposalId; + + foreach (var editGroup in proposal.Edits.GroupBy(e => e.Span.Snapshot)) + { + cancellationToken.ThrowIfCancellationRequested(); + + var snapshot = editGroup.Key; + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + + if (document is null) + continue; + + var normalizedEdits = Normalize(editGroup); + if (normalizedEdits.IsDefaultOrEmpty) + continue; + + var changeAnalysisService = document.Project.Solution.Services.GetRequiredService(); + await changeAnalysisService.AnalyzeChangeAsync( + document, normalizedEdits, proposalId, cancellationToken).ConfigureAwait(false); + } + } + + private static ImmutableArray Normalize(IEnumerable editGroup) + { + using var _ = PooledObjects.ArrayBuilder.GetInstance(out var builder); + foreach (var edit in editGroup) + builder.Add(new TextChange(edit.Span.Span.ToTextSpan(), edit.ReplacementText)); + + // Ensure everything is sorted. + builder.Sort(static (c1, c2) => c1.Span.Start - c2.Span.Start); + + // Now, go through and make sure no edit overlaps another. + for (int i = 1, n = builder.Count; i < n; i++) + { + var lastEdit = builder[i - 1]; + var currentEdit = builder[i]; + + if (lastEdit.Span.OverlapsWith(currentEdit.Span)) + return default; + } + + // Things look good. Can process these sorted edits. + return builder.ToImmutableAndClear(); + } +} diff --git a/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs new file mode 100644 index 0000000000000..5b963517f90cf --- /dev/null +++ b/src/Features/Core/Portable/Copilot/CopilotChangeAnalysis.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.Copilot; + +/// Total time to do all analysis (including diagnostics, code fixes, and application). +/// Total time to do all diagnostic computation over all diagnostic kinds. +[DataContract] +internal readonly record struct CopilotChangeAnalysis( + [property: DataMember(Order = 0)] bool Succeeded, + [property: DataMember(Order = 1)] TimeSpan TotalAnalysisTime, + [property: DataMember(Order = 2)] TimeSpan TotalDiagnosticComputationTime, + [property: DataMember(Order = 3)] ImmutableArray DiagnosticAnalyses, + [property: DataMember(Order = 4)] CopilotCodeFixAnalysis CodeFixAnalysis); + +/// What diagnostic kind this is analysis data for. +/// How long it took to produce the diagnostics for this diagnostic kind. +/// Mapping from to the number of diagnostics produced for that id. +/// Mapping from to the number of diagnostics produced for that category. +/// Mapping from to the number of diagnostics produced for that severity. +[DataContract] +internal readonly record struct CopilotDiagnosticAnalysis( + [property: DataMember(Order = 0)] DiagnosticKind Kind, + [property: DataMember(Order = 1)] TimeSpan ComputationTime, + [property: DataMember(Order = 2)] Dictionary IdToCount, + [property: DataMember(Order = 3)] Dictionary CategoryToCount, + [property: DataMember(Order = 4)] Dictionary SeverityToCount); + +/// Total time to compute code fixes for the changed regions. +/// Total time to apply code fixes for the changed regions. +/// Mapping from diagnostic id to to how many diagnostics with that id had fixes. +/// Mapping from diagnostic id to the total time taken to fix diagnostics with that id. +/// Mapping from diagnostic id to the name of the provider that provided the fix. +/// Mapping from provider name to the total time taken to fix diagnostics with that provider. +[DataContract] +internal readonly record struct CopilotCodeFixAnalysis( + [property: DataMember(Order = 0)] TimeSpan TotalComputationTime, + [property: DataMember(Order = 1)] TimeSpan TotalApplicationTime, + [property: DataMember(Order = 2)] Dictionary DiagnosticIdToCount, + [property: DataMember(Order = 3)] Dictionary DiagnosticIdToApplicationTime, + [property: DataMember(Order = 4)] Dictionary> DiagnosticIdToProviderName, + [property: DataMember(Order = 5)] Dictionary ProviderNameToApplicationTime); diff --git a/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs b/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs new file mode 100644 index 0000000000000..fd2849e1dd6d1 --- /dev/null +++ b/src/Features/Core/Portable/Copilot/ICopilotChangeAnalysisService.cs @@ -0,0 +1,87 @@ +// 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.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Copilot; + +internal interface ICopilotChangeAnalysisService : IWorkspaceService +{ + /// + /// Kicks of work to analyze a change that copilot suggested making to a document. is + /// the state of the document prior to the edits, and are the changes Copilot wants to + /// make to it. must be sorted and normalized before calling this. + /// + Task AnalyzeChangeAsync( + Document document, ImmutableArray changes, string proposalId, CancellationToken cancellationToken); +} + +[ExportWorkspaceService(typeof(ICopilotChangeAnalysisService)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DefaultCopilotChangeAnalysisService( + [Import(AllowDefault = true)] ICodeFixService? codeFixService = null, + [Import(AllowDefault = true)] IDiagnosticAnalyzerService? diagnosticAnalyzerService = null) : ICopilotChangeAnalysisService +{ +#pragma warning disable IDE0052 // Remove unread private members + private readonly ICodeFixService? _codeFixService = codeFixService; + private readonly IDiagnosticAnalyzerService? _diagnosticAnalyzerService = diagnosticAnalyzerService; +#pragma warning restore IDE0052 // Remove unread private members + + public async Task AnalyzeChangeAsync( + Document document, + ImmutableArray changes, + string proposalId, + CancellationToken cancellationToken) + { + if (!document.SupportsSemanticModel) + return default; + + Contract.ThrowIfTrue(!changes.IsSorted(static (c1, c2) => c1.Span.Start - c2.Span.Start), "'changes' was not sorted."); + Contract.ThrowIfTrue(new NormalizedTextSpanCollection(changes.Select(c => c.Span)).Count != changes.Length, "'changes' was not normalized."); + + var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); + + if (client != null) + { + var value = await client.TryInvokeAsync( + // Don't need to sync the entire solution over. Just the cone of projects this document it contained within. + document.Project, + (service, checksum, cancellationToken) => service.AnalyzeChangeAsync( + checksum, document.Id, changes, proposalId, cancellationToken), + cancellationToken).ConfigureAwait(false); + return value.HasValue ? value.Value : default; + } + else + { + return await AnalyzeChangeInCurrentProcessAsync(document, changes, cancellationToken).ConfigureAwait(false); + } + } + +#pragma warning disable CA1822 // Mark members as static +#pragma warning disable IDE0060 // Remove unused parameter +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + private async Task AnalyzeChangeInCurrentProcessAsync( + Document document, + ImmutableArray changes, + CancellationToken cancellationToken) + { + return default; + } +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously +#pragma warning restore IDE0060 // Remove unused parameter +#pragma warning restore CA1822 // Mark members as static +} diff --git a/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.cs b/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.cs new file mode 100644 index 0000000000000..fbb6347b4962b --- /dev/null +++ b/src/Features/Core/Portable/Copilot/IRemoteCopilotChangeAnalysisService.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; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Copilot; + +/// Remote version of +internal interface IRemoteCopilotChangeAnalysisService : IWorkspaceService +{ + /// + ValueTask AnalyzeChangeAsync( + Checksum solutionChecksum, DocumentId documentId, ImmutableArray edits, string proposalId, CancellationToken cancellationToken); +} diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs index 343deb91c658c..1d19cac5f4bd5 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs @@ -20,6 +20,7 @@ internal static class FeatureAttribute public const string CompletionSet = nameof(CompletionSet); public const string CopilotImplementNotImplementedException = nameof(CopilotImplementNotImplementedException); public const string CopilotSuggestions = nameof(CopilotSuggestions); + public const string CopilotChangeAnalysis = nameof(CopilotChangeAnalysis); public const string DesignerAttributes = nameof(DesignerAttributes); public const string DiagnosticService = nameof(DiagnosticService); public const string DocumentOutline = nameof(DocumentOutline); diff --git a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs index 60abbcc98f941..696b7d16f7b41 100644 --- a/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs +++ b/src/Workspaces/CoreTestUtilities/Remote/InProcRemostHostClient.cs @@ -182,6 +182,7 @@ public InProcRemoteServices(SolutionServices workspaceServices, TraceListener? t RegisterRemoteBrokeredService(new RemoteAsynchronousOperationListenerService.Factory()); RegisterRemoteBrokeredService(new RemoteCodeLensReferencesService.Factory()); RegisterRemoteBrokeredService(new RemoteConvertTupleToStructCodeRefactoringService.Factory()); + RegisterRemoteBrokeredService(new RemoteCopilotChangeAnalysisService.Factory()); RegisterRemoteBrokeredService(new RemoteDependentTypeFinderService.Factory()); RegisterRemoteBrokeredService(new RemoteDesignerAttributeDiscoveryService.Factory()); RegisterRemoteBrokeredService(new RemoteDiagnosticAnalyzerService.Factory()); diff --git a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx index 4aef0ad539f80..53e69a6905331 100644 --- a/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx +++ b/src/Workspaces/Remote/Core/RemoteWorkspacesResources.resx @@ -240,4 +240,7 @@ Initialization + + Copilot change analysis + \ No newline at end of file diff --git a/src/Workspaces/Remote/Core/ServiceDescriptors.cs b/src/Workspaces/Remote/Core/ServiceDescriptors.cs index b2e113683a662..2c88b5dee5bf4 100644 --- a/src/Workspaces/Remote/Core/ServiceDescriptors.cs +++ b/src/Workspaces/Remote/Core/ServiceDescriptors.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CodeLens; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.ConvertTupleToStruct; +using Microsoft.CodeAnalysis.Copilot; using Microsoft.CodeAnalysis.DesignerAttribute; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.DocumentHighlighting; @@ -58,6 +59,7 @@ internal sealed class ServiceDescriptors (typeof(IRemoteAsynchronousOperationListenerService), null), (typeof(IRemoteCodeLensReferencesService), null), (typeof(IRemoteConvertTupleToStructCodeRefactoringService), null), + (typeof(IRemoteCopilotChangeAnalysisService), null), (typeof(IRemoteDependentTypeFinderService), null), (typeof(IRemoteDesignerAttributeDiscoveryService), typeof(IRemoteDesignerAttributeDiscoveryService.ICallback)), (typeof(IRemoteDiagnosticAnalyzerService), null), diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf index e0cf716580e3b..32f2ea9bb8029 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.cs.xlf @@ -27,6 +27,11 @@ Převést řazenou kolekci členů na refaktoring struktury + + Copilot change analysis + Copilot change analysis + + Dependent type finder Vyhledávání závislých typů diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf index c61e7c1749e13..517d09c349fde 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.de.xlf @@ -27,6 +27,11 @@ Tupel in Strukturrefactoring konvertieren + + Copilot change analysis + Copilot change analysis + + Dependent type finder Suche nach abhängigen Typen diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf index a5cc2d538350a..1cf88210f30f2 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.es.xlf @@ -27,6 +27,11 @@ Convertir tupla en refactorización de estructura + + Copilot change analysis + Copilot change analysis + + Dependent type finder Localizador de tipos dependientes diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf index f989563604567..b87acd870b713 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.fr.xlf @@ -27,6 +27,11 @@ Refactorisation de la conversion de tuple en struct + + Copilot change analysis + Copilot change analysis + + Dependent type finder Outil de recherche de type dépendant diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf index 149c0bb4324a9..598f232526d7b 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.it.xlf @@ -27,6 +27,11 @@ Conversione della tupla nel refactoring dello struct + + Copilot change analysis + Copilot change analysis + + Dependent type finder Strumento di ricerca tipi dipendenti diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf index 282462e1a440c..1b97dcb0b6077 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ja.xlf @@ -27,6 +27,11 @@ タプルを構造体のリファクタリングに変換する + + Copilot change analysis + Copilot change analysis + + Dependent type finder 依存型の検索 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf index 85c6ac95dfffc..e16d2b7096112 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ko.xlf @@ -27,6 +27,11 @@ 튜플을 구조체 리팩터링으로 변환 + + Copilot change analysis + Copilot change analysis + + Dependent type finder 종속 형식 찾기 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf index 3e34ecd0bb45b..728fe011d135b 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pl.xlf @@ -27,6 +27,11 @@ Refaktoryzacja konwersji krotki na strukturę + + Copilot change analysis + Copilot change analysis + + Dependent type finder Wyszukiwanie typów zależnych diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf index d13db956d4483..60e3b53b5ee50 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.pt-BR.xlf @@ -27,6 +27,11 @@ Converter a tupla em refatoração de struct + + Copilot change analysis + Copilot change analysis + + Dependent type finder Localizador de tipo dependente diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf index 7ca04d5b162a3..e0418e58000df 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.ru.xlf @@ -27,6 +27,11 @@ Преобразовать кортеж в рефакторинг структуры + + Copilot change analysis + Copilot change analysis + + Dependent type finder Поиск зависимых типов diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf index c9089a3fa2f88..5b5b22d83fe3f 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.tr.xlf @@ -27,6 +27,11 @@ Demeti yapıya dönüştürme yeniden düzenlemesi + + Copilot change analysis + Copilot change analysis + + Dependent type finder Bağımlı tür bulucu diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf index 290651aa5bd14..6f6fc898759df 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hans.xlf @@ -27,6 +27,11 @@ 将元组转换为结构重构 + + Copilot change analysis + Copilot change analysis + + Dependent type finder 依赖类型查找器 diff --git a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf index ead886b90f311..b33950769abd0 100644 --- a/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Remote/Core/xlf/RemoteWorkspacesResources.zh-Hant.xlf @@ -27,6 +27,11 @@ 將元組轉換為結構重構 + + Copilot change analysis + Copilot change analysis + + Dependent type finder 相依類型尋找工具 diff --git a/src/Workspaces/Remote/ServiceHub/Services/Copilot/RemoteCopilotChangeAnalysisService.cs b/src/Workspaces/Remote/ServiceHub/Services/Copilot/RemoteCopilotChangeAnalysisService.cs new file mode 100644 index 0000000000000..a9e89cbdf36cb --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/Copilot/RemoteCopilotChangeAnalysisService.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Copilot; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteCopilotChangeAnalysisService( + in BrokeredServiceBase.ServiceConstructionArguments arguments) + : BrokeredServiceBase(arguments), IRemoteCopilotChangeAnalysisService +{ + internal sealed class Factory : FactoryBase + { + protected override IRemoteCopilotChangeAnalysisService CreateService(in ServiceConstructionArguments arguments) + => new RemoteCopilotChangeAnalysisService(arguments); + } + + public ValueTask AnalyzeChangeAsync( + Checksum solutionChecksum, + DocumentId documentId, + ImmutableArray edits, + string proposalId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => + { + var document = await solution.GetRequiredDocumentAsync( + documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + + var service = solution.Services.GetRequiredService(); + return await service.AnalyzeChangeAsync( + document, edits, proposalId, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/TextSpanMutableIntervalTree.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/TextSpanMutableIntervalTree.cs index 0c8647b4e755f..4907f3af8e306 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/TextSpanMutableIntervalTree.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/TextSpanMutableIntervalTree.cs @@ -26,4 +26,7 @@ public TextSpanMutableIntervalTree(params TextSpan[]? values) : this((IEnumerabl public bool HasIntervalThatIntersectsWith(TextSpan span) => this.HasIntervalThatIntersectsWith(span.Start, span.Length); + + public bool HasIntervalThatOverlapsWith(TextSpan span) + => this.HasIntervalThatOverlapsWith(span.Start, span.Length); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs index 1430b8477c9dc..b0264e8e72673 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs @@ -645,6 +645,8 @@ internal enum FunctionId Copilot_Implement_NotImplementedException_Failed = 831, Copilot_Implement_NotImplementedException_Completed = 832, + Copilot_AnalyzeChange = 840, + Copilot_Rename = 851, VSCode_LanguageServer_Started = 860,