Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
c1bc775
Merge branch 'updateVersions2' into autoApplyFixes
CyrusNajmabadi Jun 12, 2025
4fa5aa2
Merge branch 'speculativeEdits' into autoApplyFixes
CyrusNajmabadi Jun 12, 2025
f8b927e
Merge branch 'speculativeEdits' into autoApplyFixes
CyrusNajmabadi Jun 12, 2025
d3bc8a8
Merge branch 'speculativeEdits' into autoApplyFixes
CyrusNajmabadi Jun 12, 2025
29335ba
In progress
CyrusNajmabadi Jun 12, 2025
94680d8
Helper utility
CyrusNajmabadi Jun 12, 2025
4529f2c
in progress
CyrusNajmabadi Jun 13, 2025
e0d0e7b
MOre changes
CyrusNajmabadi Jun 13, 2025
1eb7768
Add service
CyrusNajmabadi Jun 13, 2025
6471bb8
Proposal adjustment
CyrusNajmabadi Jun 13, 2025
1cc2127
Fallback to the original set
CyrusNajmabadi Jun 13, 2025
daee2c6
Use helper
CyrusNajmabadi Jun 13, 2025
cf24809
Merge remote-tracking branch 'upstream/main' into autoApplyFixes
CyrusNajmabadi Jun 13, 2025
6ab76b2
Fix
CyrusNajmabadi Jun 13, 2025
6987ce6
Fix
CyrusNajmabadi Jun 13, 2025
df2bd2b
Merge branch 'main' into autoApplyFixes
CyrusNajmabadi Jun 13, 2025
1f25cd3
Share code
CyrusNajmabadi Jun 13, 2025
724f431
Share code
CyrusNajmabadi Jun 13, 2025
242d586
fix remote side
CyrusNajmabadi Jun 13, 2025
0906d40
Add tests
CyrusNajmabadi Jun 13, 2025
c06d131
Add tets
CyrusNajmabadi Jun 13, 2025
dc80262
Add vb tests
CyrusNajmabadi Jun 13, 2025
fdbdba5
Document cleaning
CyrusNajmabadi Jun 13, 2025
483bc78
Downstream
CyrusNajmabadi Jun 13, 2025
f05e09b
Always do syntax
CyrusNajmabadi Jun 13, 2025
f89f9c2
Always do syntax after
CyrusNajmabadi Jun 13, 2025
39dd692
Adjust before and after
CyrusNajmabadi Jun 13, 2025
95ec949
Add telemetry
CyrusNajmabadi Jun 13, 2025
092b807
Merge branch 'speculativeEdits' into autoApplyFixes
CyrusNajmabadi Jun 13, 2025
6485f02
Add speculative edits api
CyrusNajmabadi Jun 2, 2025
b5bc4cc
in progress
CyrusNajmabadi Jun 2, 2025
fd9fce5
Complete implemetnation
CyrusNajmabadi Jun 2, 2025
006f684
Comment
CyrusNajmabadi Jun 2, 2025
644412d
Add threading constraints
CyrusNajmabadi Jun 2, 2025
ea3e7c6
Separate
CyrusNajmabadi Jun 2, 2025
8ed74b8
Remove UI dep
CyrusNajmabadi Jun 2, 2025
ed224ca
Call into base
CyrusNajmabadi Jun 2, 2025
cd20aab
update versions
CyrusNajmabadi Jun 12, 2025
fefcc9e
Simplify
CyrusNajmabadi Jun 12, 2025
3f08874
update versions
CyrusNajmabadi Jun 12, 2025
ffecfcb
Simplify
CyrusNajmabadi Jun 12, 2025
e3ca928
Simplify
CyrusNajmabadi Jun 12, 2025
6c24a94
In progress
CyrusNajmabadi Jun 12, 2025
8a96a21
Helper utility
CyrusNajmabadi Jun 12, 2025
ce27d9e
in progress
CyrusNajmabadi Jun 13, 2025
c70648c
MOre changes
CyrusNajmabadi Jun 13, 2025
289fc9c
Add service
CyrusNajmabadi Jun 13, 2025
9d2c913
Proposal adjustment
CyrusNajmabadi Jun 13, 2025
9818611
Fallback to the original set
CyrusNajmabadi Jun 13, 2025
d5f9490
Use helper
CyrusNajmabadi Jun 13, 2025
5daa687
Fix
CyrusNajmabadi Jun 13, 2025
2822fc9
Fix
CyrusNajmabadi Jun 13, 2025
f47f132
Share code
CyrusNajmabadi Jun 13, 2025
385ed4a
Share code
CyrusNajmabadi Jun 13, 2025
8b212c6
fix remote side
CyrusNajmabadi Jun 13, 2025
6680585
Add tests
CyrusNajmabadi Jun 13, 2025
10402e7
Add tets
CyrusNajmabadi Jun 13, 2025
9e7d073
Add vb tests
CyrusNajmabadi Jun 13, 2025
24fcf8b
Document cleaning
CyrusNajmabadi Jun 13, 2025
2515934
Downstream
CyrusNajmabadi Jun 13, 2025
8e88735
Always do syntax
CyrusNajmabadi Jun 13, 2025
4d5d88e
Always do syntax after
CyrusNajmabadi Jun 13, 2025
6b1f61b
Adjust before and after
CyrusNajmabadi Jun 13, 2025
bbbb52d
Add telemetry
CyrusNajmabadi Jun 13, 2025
f8f6082
Merge branch 'autoApplyFixes' of https://github.com/CyrusNajmabadi/ro…
CyrusNajmabadi Jun 17, 2025
3339942
Merge branch 'speculativeEdits' into autoApplyFixes
CyrusNajmabadi Jun 17, 2025
2e60831
Merge branch 'main-vs-deps' into autoApplyFixes
CyrusNajmabadi Jun 18, 2025
ca44ecf
Merge branch 'main-vs-deps' into autoApplyFixes
CyrusNajmabadi Jun 19, 2025
dad809b
Update src/EditorFeatures/Core/Copilot/CopilotEditorUtilities.cs
CyrusNajmabadi Jun 19, 2025
1dd148e
Update src/EditorFeatures/Core/Copilot/CopilotEditorUtilities.cs
CyrusNajmabadi Jun 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/targets/Services.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.CompilationAvailable" ClassName="Microsoft.CodeAnalysis.Remote.RemoteCompilationAvailableService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.ConvertTupleToStructCodeRefactoring" ClassName="Microsoft.CodeAnalysis.Remote.RemoteConvertTupleToStructCodeRefactoringService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.CopilotChangeAnalysis" ClassName="Microsoft.CodeAnalysis.Remote.RemoteCopilotChangeAnalysisService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.CopilotProposalAdjuster" ClassName="Microsoft.CodeAnalysis.Remote.RemoteCopilotProposalAdjusterService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.DependentTypeFinder" ClassName="Microsoft.CodeAnalysis.Remote.RemoteDependentTypeFinderService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.DesignerAttributeDiscovery" ClassName="Microsoft.CodeAnalysis.Remote.RemoteDesignerAttributeDiscoveryService+Factory" />
<ServiceHubService Include="Microsoft.VisualStudio.LanguageServices.DiagnosticAnalyzer" ClassName="Microsoft.CodeAnalysis.Remote.RemoteDiagnosticAnalyzerService+Factory" />
Expand Down
52 changes: 52 additions & 0 deletions src/EditorFeatures/Core/Copilot/CopilotEditorUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Language.Proposals;

namespace Microsoft.CodeAnalysis.Copilot;

internal static class CopilotEditorUtilities
{
public static Solution? TryGetAffectedSolution(ProposalBase proposal)
{
Solution? solution = null;
foreach (var edit in proposal.Edits)
{
var document = edit.Span.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

// Edit touches a file roslyn doesn't know about. Don't touch this.
if (document is null)
return null;

// Only bother for languages we can actually process semantics for.
if (document.SupportsSemanticModel)
return null;

var currentSolution = document.Project.Solution;

// Edit touches multiple solutions. Don't bother with this for now for simplicity's sake.
if (solution != null && solution != currentSolution)
return null;

solution = currentSolution;
}

return solution;
}

public static ImmutableArray<TextChange> TryGetNormalizedTextChanges(IEnumerable<ProposedEdit> edits)
{
using var _ = ArrayBuilder<TextChange>.GetInstance(out var textChanges);
foreach (var edit in edits)
textChanges.Add(new TextChange(edit.Span.Span.ToTextSpan(), edit.ReplacementText));

return CopilotUtilities.TryNormalizeCopilotTextChanges(textChanges);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Threading;
Expand Down Expand Up @@ -106,6 +107,14 @@ private static async ValueTask ProcessCompletionEventAsync(
const string featureId = "Completion";
var proposalId = proposal.ProposalId;

var solution = CopilotEditorUtilities.TryGetAffectedSolution(proposal);
if (solution is null)
return;

// We're about to potentially make multiple calls to oop here. So keep a session alive to avoid
// resyncing any data unnecessary.
using var _1 = await RemoteKeepAliveSession.CreateAsync(solution, cancellationToken).ConfigureAwait(false);

foreach (var editGroup in proposal.Edits.GroupBy(e => e.Span.Snapshot))
{
cancellationToken.ThrowIfCancellationRequested();
Expand All @@ -116,12 +125,10 @@ private static async ValueTask ProcessCompletionEventAsync(
if (document is null)
continue;

using var _ = PooledObjects.ArrayBuilder<TextChange>.GetInstance(out var textChanges);
foreach (var edit in editGroup)
textChanges.Add(new TextChange(edit.Span.Span.ToTextSpan(), edit.ReplacementText));
var normalizedEdits = CopilotEditorUtilities.TryGetNormalizedTextChanges(editGroup);

await CopilotChangeAnalysisUtilities.AnalyzeCopilotChangeAsync(
document, accepted, featureId, proposalId, textChanges, cancellationToken).ConfigureAwait(false);
document, accepted, featureId, proposalId, normalizedEdits, cancellationToken).ConfigureAwait(false);
}
}
}
120 changes: 120 additions & 0 deletions src/EditorFeatures/Core/Copilot/RoslynProposalAdjusterProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Language.Proposals;
using Microsoft.VisualStudio.Utilities;

namespace Microsoft.CodeAnalysis.Copilot;

// The entire AdjusterProvider api is marked as obsolete since this is a preview API. So we do the same here as well.
[Obsolete("This is a preview api and subject to change")]
[ContentType(ContentTypeNames.RoslynContentType)]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class RoslynProposalAdjusterProvider() : ProposalAdjusterProviderBase
{
public override Task<ProposalBase> AdjustProposalBeforeDisplayAsync(ProposalBase proposal, string providerName, CancellationToken cancellationToken)
=> AdjustProposalAsync(proposal, providerName, before: true, cancellationToken);

public override Task<ProposalBase> AdjustProposalAfterAcceptAsync(ProposalBase proposal, string providerName, CancellationToken cancellationToken)
=> AdjustProposalAsync(proposal, providerName, before: false, cancellationToken);

private async Task<ProposalBase> AdjustProposalAsync(
ProposalBase proposal, string providerName, bool before, CancellationToken cancellationToken)
{
// Ensure we're only operating on one solution. It makes the logic much simpler, as we don't have to
// worry about edits that touch multiple solutions.
var solution = CopilotEditorUtilities.TryGetAffectedSolution(proposal);
if (solution is null)
return proposal;

// We're potentially making multiple calls to oop here. So keep a session alive to avoid
// resyncing the solution and recomputing compilations.
using var _1 = await RemoteKeepAliveSession.CreateAsync(solution, cancellationToken).ConfigureAwait(false);
using var _2 = PooledObjects.ArrayBuilder<ProposedEdit>.GetInstance(out var finalEdits);

var adjustmentsProposed = false;
foreach (var editGroup in proposal.Edits.GroupBy(e => e.Span.Snapshot))
{
cancellationToken.ThrowIfCancellationRequested();

var snapshot = editGroup.Key;
var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();

// Checked in TryGetAffectedSolution
Contract.ThrowIfNull(document);

var proposedEdits = await TryAdjustProposalDisplayAsync(
document, CopilotEditorUtilities.TryGetNormalizedTextChanges(editGroup), cancellationToken).ConfigureAwait(false);

if (proposedEdits.IsDefault)
{
// No changes were made to the proposal. Just add the original edits.
finalEdits.AddRange(editGroup);
}
else
{
// Changes were made to the proposal. Add the new edits.
adjustmentsProposed = true;
foreach (var proposedEdit in proposedEdits)
{
finalEdits.Add(new ProposedEdit(
new(snapshot, proposedEdit.Span.ToSpan()),
proposedEdit.NewText!));
}
}
}

// No adjustments were made. Don't touch anything.
if (!adjustmentsProposed)
{
using var _3 = Logger.LogBlock(FunctionId.Copilot_AdjustProposal, KeyValueLogMessage.Create(static (d, args) =>
{
var (providerName, before) = args;
d["ProviderName"] = providerName;
d["Before"] = before;
d["AdjustmentsProposed"] = false;
},
args: (providerName, before)),
cancellationToken);

return proposal;
}

var newProposal = Proposal.TryCreateProposal(proposal, finalEdits);

using var _4 = Logger.LogBlock(FunctionId.Copilot_AdjustProposal, KeyValueLogMessage.Create(static (d, args) =>
{
var (providerName, before, newProposal) = args;
d["ProviderName"] = providerName;
d["Before"] = before;
d["AdjustmentsProposed"] = true;
d["AdjustmentsAccepted"] = newProposal != null;
},
args: (providerName, before, newProposal)),
cancellationToken);

return newProposal ?? proposal;
}

private async Task<ImmutableArray<TextChange>> TryAdjustProposalDisplayAsync(
Document document, ImmutableArray<TextChange> normalizedChanges, CancellationToken cancellationToken)
{
var proposalAdjusterService = document.Project.Solution.Services.GetRequiredService<ICopilotProposalAdjusterService>();
return await proposalAdjusterService.TryAdjustProposalAsync(
document, normalizedChanges, cancellationToken).ConfigureAwait(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,29 @@

namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTestGenerator.Api;

[Export]
[Shared]
#pragma warning disable CA1822 // Mark members as static. Existing binary api with UnitTestGenerator.

[Export, Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal class UnitTestGeneratorAddMissingImportsFeatureServiceAccessor()
{
#pragma warning disable CA1822 // Mark members as static
internal async Task<Document> AddMissingImportsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
#pragma warning restore CA1822
{
var service = document.Project.GetRequiredLanguageService<IAddMissingImportsFeatureService>();

// Unfortunately, the unit testing system doesn't have a way to report progress.
return await service.AddMissingImportsAsync(document, textSpan, CodeAnalysisProgress.None, cancellationToken).ConfigureAwait(false);
}

#pragma warning disable CA1822 // Mark members as static
internal async Task<WrappedMissingImportsAnalysisResult> AnalyzeAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
#pragma warning restore CA1822
{
var service = document.Project.GetRequiredLanguageService<IAddMissingImportsFeatureService>();
var result = await service.AnalyzeAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
var result = await service.AnalyzeAsync(document, textSpan, cleanupDocument: true, cancellationToken).ConfigureAwait(false);
return new WrappedMissingImportsAnalysisResult(result.SelectAsArray(data => new WrappedAddImportFixData(data)));
}

#pragma warning disable CA1822 // Mark members as static
internal async Task<Document> AddMissingImportsAsync(Document document, WrappedMissingImportsAnalysisResult analysisResult, CancellationToken cancellationToken)
#pragma warning restore CA1822
{
var service = document.Project.GetRequiredLanguageService<IAddMissingImportsFeatureService>();
var unwrappedResult = analysisResult.AddImportFixDatas.SelectAsArray(result => result.Underlying);
Expand Down
Loading
Loading