diff --git a/.github/workflows/main-merge.yml b/.github/workflows/main-merge.yml
index f00b43ac01a49..73424ad35fad6 100644
--- a/.github/workflows/main-merge.yml
+++ b/.github/workflows/main-merge.yml
@@ -5,6 +5,9 @@ on:
schedule:
# Create a merge every 3 hours (works only for merges from `main`, others would need a `push` trigger).
- cron: '0 */3 * * *'
+ push:
+ branches:
+ - main-vs-deps
workflow_dispatch:
inputs:
configuration_file_branch:
@@ -17,17 +20,9 @@ permissions:
pull-requests: write
jobs:
- # The config does not support multiple flows from the same source branch,
- # so we need to run separately for each duplicate source branch (https://github.com/dotnet/arcade/issues/15586).
merge:
if: github.repository == 'dotnet/roslyn'
uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@main
with:
configuration_file_path: 'eng/config/branch-merge.jsonc'
configuration_file_branch: ${{ inputs.configuration_file_branch || 'main' }}
- merge-2:
- if: github.repository == 'dotnet/roslyn'
- uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@main
- with:
- configuration_file_path: 'eng/config/branch-merge-2.jsonc'
- configuration_file_branch: ${{ inputs.configuration_file_branch || 'main' }}
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index d86c5d196dcac..5d1b41f1f115a 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -8,9 +8,9 @@
-
+
https://github.com/dotnet/source-build-reference-packages
- c3d4c372a15c2de79a2f26fe2b6b3644996d8550
+ 12b07db19093502e1530df6058699bb43bb9b4ba
diff --git a/eng/config/branch-merge-2.jsonc b/eng/config/branch-merge-2.jsonc
deleted file mode 100644
index cd979074b54a4..0000000000000
--- a/eng/config/branch-merge-2.jsonc
+++ /dev/null
@@ -1,10 +0,0 @@
-// Used by .github/workflows/main-merge.yml
-{
- "merge-flow-configurations": {
- // Merge any main changes to main-vs-deps.
- "main": {
- "MergeToBranch": "main-vs-deps",
- "ExtraSwitches": "-QuietComments"
- }
- }
-}
diff --git a/eng/config/branch-merge.jsonc b/eng/config/branch-merge.jsonc
index bd198290691b3..7cdbfe60c8de2 100644
--- a/eng/config/branch-merge.jsonc
+++ b/eng/config/branch-merge.jsonc
@@ -1,8 +1,13 @@
// Used by .github/workflows/main-merge.yml
{
"merge-flow-configurations": {
- // Merge any main changes to release/dev18.0.
+ // Merge any main changes to main-vs-deps.
"main": {
+ "MergeToBranch": "main-vs-deps",
+ "ExtraSwitches": "-QuietComments"
+ },
+ // Merge any main-vs-deps changes to release/dev18.0.
+ "main-vs-deps": {
"MergeToBranch": "release/dev18.0",
"ExtraSwitches": "-QuietComments"
}
diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs
index 61c3f93529acf..90799128f9b1f 100644
--- a/src/Compilers/Test/Core/Traits/Traits.cs
+++ b/src/Compilers/Test/Core/Traits/Traits.cs
@@ -290,6 +290,7 @@ public static class Features
public const string NetCore = nameof(NetCore);
public const string NormalizeModifiersOrOperators = nameof(NormalizeModifiersOrOperators);
public const string ObjectBrowser = nameof(ObjectBrowser);
+ public const string OnTheFlyDocs = nameof(OnTheFlyDocs);
public const string Options = nameof(Options);
public const string Organizing = nameof(Organizing);
public const string Outlining = nameof(Outlining);
diff --git a/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs b/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs
new file mode 100644
index 0000000000000..d52c79cb9d1c3
--- /dev/null
+++ b/src/EditorFeatures/CSharpTest/OnTheFlyDocs/OnTheFlyDocsUtilitiesTests.cs
@@ -0,0 +1,130 @@
+// 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.Linq;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CSharp.QuickInfo;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.OnTheFlyDocs;
+
+[UseExportProvider]
+[Trait(Traits.Feature, Traits.Features.OnTheFlyDocs)]
+public sealed class OnTheFlyDocsUtilitiesTests
+{
+ [Fact]
+ public async Task TestAdditionalContextNoContext()
+ {
+ var testCode = """
+ class C
+ {
+ void AddMethod(int a, int b)
+ {
+ return a + b;
+ }
+ }
+ """;
+
+ using var workspace = EditorTestWorkspace.CreateCSharp(testCode);
+ var solution = workspace.CurrentSolution;
+ var document = solution.Projects.First().Documents.First();
+
+ var syntaxTree = await document.GetSyntaxTreeAsync();
+ var semanticModel = await document.GetSemanticModelAsync();
+
+ var methodDeclaration = syntaxTree!.GetRoot()
+ .DescendantNodes()
+ .OfType()
+ .First();
+
+ var methodSymbol = semanticModel!.GetDeclaredSymbol(methodDeclaration);
+
+ var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!);
+ Assert.True(result.All(item => item == null));
+ }
+
+ [Fact]
+ public async Task TestAdditionalContextWithTypeParameters()
+ {
+ var testCode = """
+ class C
+ {
+ int AddMethod(A a, int b)
+ {
+ return a.x + b;
+ }
+ }
+
+ class A
+ {
+ public int x;
+ }
+ """;
+
+ using var workspace = EditorTestWorkspace.CreateCSharp(testCode);
+ var solution = workspace.CurrentSolution;
+ var document = solution.Projects.First().Documents.First();
+
+ var syntaxTree = await document.GetSyntaxTreeAsync();
+ var semanticModel = await document.GetSemanticModelAsync();
+
+ var methodDeclaration = syntaxTree!.GetRoot()
+ .DescendantNodes()
+ .OfType()
+ .First();
+
+ var methodSymbol = semanticModel!.GetDeclaredSymbol(methodDeclaration);
+
+ var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!);
+ Assert.NotNull(result.First());
+ Assert.Null(result.Last());
+ }
+
+ [Fact]
+ public async Task TestAdditionalContextWithTypeArguments()
+ {
+ var testCode = """
+ class C
+ {
+ void Method(T t, U u) where T : class where U : struct
+ {
+ }
+
+ void CallMethod()
+ {
+ Method(new CustomClass(), new CustomStruct());
+ }
+ }
+
+ class CustomClass
+ {
+ public string Name { get; set; }
+ }
+
+ struct CustomStruct
+ {
+ public int Value { get; set; }
+ }
+ """;
+
+ using var workspace = EditorTestWorkspace.CreateCSharp(testCode);
+ var solution = workspace.CurrentSolution;
+ var document = solution.Projects.First().Documents.First();
+
+ var syntaxTree = await document.GetSyntaxTreeAsync();
+ var semanticModel = await document.GetSemanticModelAsync();
+
+ var methodInvocation = syntaxTree!.GetRoot()
+ .DescendantNodes()
+ .OfType()
+ .First();
+
+ var methodSymbol = semanticModel!.GetSymbolInfo(methodInvocation).Symbol;
+
+ var result = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, methodSymbol!);
+ Assert.True(result.All(item => item is not null));
+ }
+}
diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs
index 424d1c8c775d2..b9908ef2dbf80 100644
--- a/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs
+++ b/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs
@@ -179,7 +179,8 @@ private async Task SetResultTextAsync(ICopilotCodeAnalysisService copilotService
try
{
- var (responseString, isQuotaExceeded) = await copilotService.GetOnTheFlyDocsAsync(_onTheFlyDocsInfo.SymbolSignature, _onTheFlyDocsInfo.DeclarationCode, _onTheFlyDocsInfo.Language, cancellationToken).ConfigureAwait(false);
+ var prompt = await copilotService.GetOnTheFlyDocsPromptAsync(_onTheFlyDocsInfo, cancellationToken).ConfigureAwait(false);
+ var (responseString, isQuotaExceeded) = await copilotService.GetOnTheFlyDocsResponseAsync(prompt, cancellationToken).ConfigureAwait(false);
var copilotRequestTime = stopwatch.Elapsed;
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
index 254c213025a31..cab76f41eba63 100644
--- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
+++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb
@@ -19,6 +19,7 @@ Imports Microsoft.CodeAnalysis.ErrorLogger
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
+Imports Microsoft.CodeAnalysis.QuickInfo
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.UnitTests
Imports Roslyn.Utilities
@@ -359,10 +360,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests
Return Task.CompletedTask
End Function
- Public Function GetOnTheFlyDocsAsync(symbolSignature As String, declarationCode As ImmutableArray(Of String), language As String, cancellationToken As CancellationToken) As Task(Of (responseString As String, isQuotaExceeded As Boolean)) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsAsync
- Return Task.FromResult(("", False))
- End Function
-
Public Function IsFileExcludedAsync(filePath As String, cancellationToken As CancellationToken) As Task(Of Boolean) Implements ICopilotCodeAnalysisService.IsFileExcludedAsync
Return Task.FromResult(False)
End Function
@@ -371,6 +368,14 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests
Return Task.FromResult((New Dictionary(Of String, String), False))
End Function
+ Public Function GetOnTheFlyDocsPromptAsync(onTheFlyDocsInfo As OnTheFlyDocsInfo, cancellationToken As CancellationToken) As Task(Of String) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsPromptAsync
+ Return Task.FromResult(String.Empty)
+ End Function
+
+ Public Function GetOnTheFlyDocsResponseAsync(prompt As String, cancellationToken As CancellationToken) As Task(Of (responseString As String, isQuotaExceeded As Boolean)) Implements ICopilotCodeAnalysisService.GetOnTheFlyDocsResponseAsync
+ Return Task.FromResult((String.Empty, False))
+ End Function
+
Public Function IsImplementNotImplementedExceptionsAvailableAsync(cancellationToken As CancellationToken) As Task(Of Boolean) Implements ICopilotCodeAnalysisService.IsImplementNotImplementedExceptionsAvailableAsync
Return Task.FromResult(False)
End Function
diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs
index 81fd490ab6f3e..96b38b78d4825 100644
--- a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs
+++ b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs
@@ -193,14 +193,21 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant
}
}
- var maxLength = 1000;
- var symbolStrings = symbol.DeclaringSyntaxReferences.Select(reference =>
+ var solution = document.Project.Solution;
+ var declarationCode = symbol.DeclaringSyntaxReferences.Select(reference =>
{
var span = reference.Span;
- var sourceText = reference.SyntaxTree.GetText(cancellationToken);
- return sourceText.GetSubText(new Text.TextSpan(span.Start, Math.Min(maxLength, span.Length))).ToString();
+ var syntaxReferenceDocument = solution.GetDocument(reference.SyntaxTree);
+ if (syntaxReferenceDocument is not null)
+ {
+ return new OnTheFlyDocsRelevantFileInfo(syntaxReferenceDocument, span);
+ }
+
+ return null;
}).ToImmutableArray();
- return new OnTheFlyDocsInfo(symbol.ToDisplayString(), symbolStrings, symbol.Language, hasContentExcluded);
+ var additionalContext = OnTheFlyDocsUtilities.GetAdditionalOnTheFlyDocsContext(solution, symbol);
+
+ return new OnTheFlyDocsInfo(symbol.ToDisplayString(), declarationCode, symbol.Language, hasContentExcluded, additionalContext);
}
}
diff --git a/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.cs b/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.cs
new file mode 100644
index 0000000000000..74779aebf1546
--- /dev/null
+++ b/src/Features/CSharp/Portable/QuickInfo/OnTheFlyDocsUtilities.cs
@@ -0,0 +1,50 @@
+// 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.Linq;
+using Microsoft.CodeAnalysis.QuickInfo;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+
+namespace Microsoft.CodeAnalysis.CSharp.QuickInfo;
+
+internal static class OnTheFlyDocsUtilities
+{
+ public static ImmutableArray GetAdditionalOnTheFlyDocsContext(Solution solution, ISymbol symbol)
+ {
+ var parameters = symbol.GetParameters();
+ var typeArguments = symbol.GetTypeArguments();
+
+ var parameterStrings = parameters.Select(parameter =>
+ {
+ var typeSymbol = parameter.Type;
+ return GetOnTheFlyDocsRelevantFileInfo(typeSymbol);
+
+ }).ToImmutableArray();
+
+ var typeArgumentStrings = typeArguments.Select(typeArgument =>
+ {
+ return GetOnTheFlyDocsRelevantFileInfo(typeArgument);
+
+ }).ToImmutableArray();
+
+ return parameterStrings.AddRange(typeArgumentStrings);
+
+ OnTheFlyDocsRelevantFileInfo? GetOnTheFlyDocsRelevantFileInfo(ITypeSymbol typeSymbol)
+ {
+ var typeSyntaxReference = typeSymbol.DeclaringSyntaxReferences.FirstOrDefault();
+ if (typeSyntaxReference is not null)
+ {
+ var typeSpan = typeSyntaxReference.Span;
+ var syntaxReferenceDocument = solution.GetDocument(typeSyntaxReference.SyntaxTree);
+ if (syntaxReferenceDocument is not null)
+ {
+ return new OnTheFlyDocsRelevantFileInfo(syntaxReferenceDocument, typeSpan);
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs
index 31c40582322a0..1bd47a290ce1f 100644
--- a/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs
+++ b/src/Features/CSharpTest/Copilot/CSharpImplementNotImplementedExceptionFixProviderTests.cs
@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.CodeAnalysis.Text;
@@ -696,5 +697,15 @@ public Task IsImplementNotImplementedExceptionsAvailableAsync(Cancellation
{
return Task.FromResult(true);
}
+
+ public Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs
index 9b294d5a002b6..0df44b14c6463 100644
--- a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs
+++ b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs
@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.DocumentationComments;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Copilot;
@@ -65,15 +66,17 @@ internal interface ICopilotCodeAnalysisService : ILanguageService
Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken);
///
- /// Method to fetch the on-the-fly documentation based on a a symbols
- /// and the code for the symbols in .
- ///
- /// is a formatted string representation of an .
- /// is a list of a code definitions from an .
- /// is the language of the originating .
- ///
+ /// Retrieves the prompt
///
- Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken);
+ /// Type containing code and other context about the symbol being examined.
+ ///
+ Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken);
+
+ ///
+ /// Retrieves the response from Copilot summarizing what a symbol is being used for and whether or not the quota has exceeded.
+ ///
+ /// The input text used to generate the response.
+ Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken);
///
/// Determines if the given is excluded in the workspace.
diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs
index c1a69a7d374ff..2e46a28525140 100644
--- a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs
+++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs
@@ -13,12 +13,13 @@ namespace Microsoft.CodeAnalysis.QuickInfo;
/// the symbol's declaration code
/// the language of the symbol
/// whether the symbol has comments
-internal sealed class OnTheFlyDocsInfo(string symbolSignature, ImmutableArray declarationCode, string language, bool isContentExcluded, bool hasComments = false)
+internal sealed class OnTheFlyDocsInfo(string symbolSignature, ImmutableArray declarationCode, string language, bool isContentExcluded, ImmutableArray additionalContext, bool hasComments = false)
{
public string SymbolSignature { get; } = symbolSignature;
- public ImmutableArray DeclarationCode { get; } = declarationCode;
+ public ImmutableArray DeclarationCode { get; } = declarationCode;
public string Language { get; } = language;
public bool IsContentExcluded { get; set; } = isContentExcluded;
+ public ImmutableArray AdditionalContext { get; } = additionalContext;
// Added for telemetry collection purposes.
public bool HasComments { get; set; } = hasComments;
diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.cs
new file mode 100644
index 0000000000000..aa5390dac3e35
--- /dev/null
+++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsRelevantFileInfo.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 Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.QuickInfo;
+
+internal sealed record OnTheFlyDocsRelevantFileInfo
+{
+ public Document Document { get; }
+ public TextSpan TextSpan { get; }
+
+ public OnTheFlyDocsRelevantFileInfo(Document document, TextSpan textSpan)
+ {
+ Document = document;
+ TextSpan = textSpan;
+ }
+}
+
diff --git a/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs
index 8bd3c115522e8..397b31031be87 100644
--- a/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs
+++ b/src/Features/ExternalAccess/Copilot/Analyzer/IExternalCSharpCopilotCodeAnalysisService.cs
@@ -17,6 +17,5 @@ internal interface IExternalCSharpCopilotCodeAnalysisService
Task> AnalyzeDocumentAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken);
Task> GetCachedDiagnosticsAsync(Document document, string promptTitle, CancellationToken cancellationToken);
Task StartRefinementSessionAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken);
- Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken);
Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken);
}
diff --git a/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs
index a783f1bf7eae6..e5ae13688b414 100644
--- a/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs
+++ b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/AbstractCopilotCodeAnalysisService.cs
@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.DocumentationComments;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
@@ -41,7 +42,8 @@ internal abstract class AbstractCopilotCodeAnalysisService(IDiagnosticsRefresher
protected abstract Task> AnalyzeDocumentCoreAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken);
protected abstract Task> GetCachedDiagnosticsCoreAsync(Document document, string promptTitle, CancellationToken cancellationToken);
protected abstract Task StartRefinementSessionCoreAsync(Document oldDocument, Document newDocument, Diagnostic? primaryDiagnostic, CancellationToken cancellationToken);
- protected abstract Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsCoreAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken);
+ protected abstract Task GetOnTheFlyDocsPromptCoreAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken);
+ protected abstract Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseCoreAsync(string prompt, CancellationToken cancellationToken);
protected abstract Task IsFileExcludedCoreAsync(string filePath, CancellationToken cancellationToken);
protected abstract Task<(Dictionary? responseDictionary, bool isQuotaExceeded)> GetDocumentationCommentCoreAsync(DocumentationCommentProposal proposal, CancellationToken cancellationToken);
protected abstract Task> ImplementNotImplementedExceptionsCoreAsync(Document document, ImmutableDictionary> methodOrProperties, CancellationToken cancellationToken);
@@ -178,12 +180,16 @@ public async Task StartRefinementSessionAsync(Document oldDocument, Document new
await StartRefinementSessionCoreAsync(oldDocument, newDocument, primaryDiagnostic, cancellationToken).ConfigureAwait(false);
}
- public async Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken)
+ public async Task GetOnTheFlyDocsPromptAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken)
+ {
+ return await GetOnTheFlyDocsPromptCoreAsync(onTheFlyDocsInfo, cancellationToken).ConfigureAwait(false);
+ }
+ public async Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken)
{
if (!await IsAvailableAsync(cancellationToken).ConfigureAwait(false))
return (string.Empty, false);
- return await GetOnTheFlyDocsCoreAsync(symbolSignature, declarationCode, language, cancellationToken).ConfigureAwait(false);
+ return await GetOnTheFlyDocsResponseCoreAsync(prompt, cancellationToken).ConfigureAwait(false);
}
public async Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken)
diff --git a/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs
index eb00e458c3742..7b64e019e5f80 100644
--- a/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs
+++ b/src/Features/ExternalAccess/Copilot/Internal/Analyzer/CSharp/CSharpCopilotCodeAnalysisService.cs
@@ -18,6 +18,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
@@ -28,6 +29,7 @@ internal sealed class CSharpCopilotCodeAnalysisService : AbstractCopilotCodeAnal
{
private IExternalCSharpCopilotCodeAnalysisService? AnalysisService { get; }
private IExternalCSharpCopilotGenerateDocumentationService? GenerateDocumentationService { get; }
+ private IExternalCSharpOnTheFlyDocsService? OnTheFlyDocsService { get; }
private IExternalCSharpCopilotGenerateImplementationService? GenerateImplementationService { get; }
[ImportingConstructor]
@@ -35,22 +37,26 @@ internal sealed class CSharpCopilotCodeAnalysisService : AbstractCopilotCodeAnal
public CSharpCopilotCodeAnalysisService(
[Import(AllowDefault = true)] IExternalCSharpCopilotCodeAnalysisService? externalCopilotService,
[Import(AllowDefault = true)] IExternalCSharpCopilotGenerateDocumentationService? externalCSharpCopilotGenerateDocumentationService,
+ [Import(AllowDefault = true)] IExternalCSharpOnTheFlyDocsService? externalCSharpOnTheFlyDocsService,
[Import(AllowDefault = true)] IExternalCSharpCopilotGenerateImplementationService? externalCSharpCopilotGenerateImplementationService,
IDiagnosticsRefresher diagnosticsRefresher
) : base(diagnosticsRefresher)
{
if (externalCopilotService is null)
- FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpCopilotGenerateDocumentationService)), ErrorSeverity.Diagnostic);
+ FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCopilotService)), ErrorSeverity.Diagnostic);
if (externalCSharpCopilotGenerateDocumentationService is null)
FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpCopilotGenerateDocumentationService)), ErrorSeverity.Diagnostic);
- if (externalCSharpCopilotGenerateDocumentationService is null)
+ if (externalCSharpOnTheFlyDocsService is null)
+ FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpOnTheFlyDocsService)), ErrorSeverity.Diagnostic);
+
+ if (externalCSharpCopilotGenerateImplementationService is null)
FatalError.ReportAndCatch(new ArgumentNullException(nameof(externalCSharpCopilotGenerateImplementationService)), ErrorSeverity.Diagnostic);
AnalysisService = externalCopilotService;
GenerateDocumentationService = externalCSharpCopilotGenerateDocumentationService;
- GenerateImplementationService = externalCSharpCopilotGenerateImplementationService;
+ OnTheFlyDocsService = externalCSharpOnTheFlyDocsService;
}
protected override Task> AnalyzeDocumentCoreAsync(Document document, TextSpan? span, string promptTitle, CancellationToken cancellationToken)
@@ -93,10 +99,18 @@ protected override Task StartRefinementSessionCoreAsync(Document oldDocument, Do
return Task.CompletedTask;
}
- protected override Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsCoreAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken)
+ protected override Task GetOnTheFlyDocsPromptCoreAsync(OnTheFlyDocsInfo onTheFlyDocsInfo, CancellationToken cancellationToken)
{
- if (AnalysisService is not null)
- return AnalysisService.GetOnTheFlyDocsAsync(symbolSignature, declarationCode, language, cancellationToken);
+ if (OnTheFlyDocsService is not null)
+ return OnTheFlyDocsService.GetOnTheFlyDocsPromptAsync(new CopilotOnTheFlyDocsInfoWrapper(onTheFlyDocsInfo), cancellationToken);
+
+ return Task.FromResult(string.Empty);
+ }
+
+ protected override Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseCoreAsync(string prompt, CancellationToken cancellationToken)
+ {
+ if (OnTheFlyDocsService is not null)
+ return OnTheFlyDocsService.GetOnTheFlyDocsResponseAsync(prompt, cancellationToken);
return Task.FromResult((string.Empty, false));
}
diff --git a/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
index 3f5b1f9b5612a..52c76edce89ff 100644
--- a/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
+++ b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
@@ -18,6 +18,18 @@ Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Returns = 3 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.Summary = 0 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType.TypeParam = 1 -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentTagType
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.AdditionalContext.get -> System.Collections.Immutable.ImmutableArray
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.CopilotOnTheFlyDocsInfoWrapper(Microsoft.CodeAnalysis.QuickInfo.OnTheFlyDocsInfo! onTheFlyDocsInfo) -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.DeclarationCode.get -> System.Collections.Immutable.ImmutableArray
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.HasComments.get -> bool
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.IsContentExcluded.get -> bool
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.Language.get -> string!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper.SymbolSignature.get -> string!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.CopilotOnTheFlyDocsRelevantFileInfoWrapper(Microsoft.CodeAnalysis.QuickInfo.OnTheFlyDocsRelevantFileInfo! onTheFlyDocsRelevantFileInfo) -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.Document.get -> Microsoft.CodeAnalysis.Document!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsRelevantFileInfoWrapper.TextSpan.get -> Microsoft.CodeAnalysis.Text.TextSpan
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities
Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper
Microsoft.CodeAnalysis.ExternalAccess.Copilot.GenerateImplementation.ImplementationDetailsWrapper.ImplementationDetailsWrapper() -> void
@@ -35,6 +47,9 @@ Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysis
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotCodeAnalysisService.StartRefinementSessionAsync(Microsoft.CodeAnalysis.Document! oldDocument, Microsoft.CodeAnalysis.Document! newDocument, Microsoft.CodeAnalysis.Diagnostic? primaryDiagnostic, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateDocumentationService
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateDocumentationService.GetDocumentationCommentAsync(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper! proposal, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(System.Collections.Generic.Dictionary? responseDictionary, bool isQuotaExceeded)>!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService.GetOnTheFlyDocsPromptAsync(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotOnTheFlyDocsInfoWrapper! onTheFlyDocsInfo, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpOnTheFlyDocsService.GetOnTheFlyDocsResponseAsync(string! prompt, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(string! responseString, bool isQuotaExceeded)>!
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateImplementationService
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateImplementationService.ImplementNotImplementedExceptionsAsync(Microsoft.CodeAnalysis.Document! document, System.Collections.Immutable.ImmutableDictionary>! methodOrProperties, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!>!
Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments.ICopilotRelatedDocumentsService
diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.cs
new file mode 100644
index 0000000000000..c7e1cb312b447
--- /dev/null
+++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsInfoWrapper.cs
@@ -0,0 +1,31 @@
+// 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 Microsoft.CodeAnalysis.QuickInfo;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot;
+
+internal sealed class CopilotOnTheFlyDocsInfoWrapper
+{
+ private readonly OnTheFlyDocsInfo _onTheFlyDocsInfo;
+ private readonly ImmutableArray _wrappedDeclarationCode;
+ private readonly ImmutableArray _wrappedAdditionalContext;
+
+ public CopilotOnTheFlyDocsInfoWrapper(OnTheFlyDocsInfo onTheFlyDocsInfo)
+ {
+ _onTheFlyDocsInfo = onTheFlyDocsInfo;
+ _wrappedDeclarationCode = _onTheFlyDocsInfo.DeclarationCode.SelectAsArray(c => c is not null ? new CopilotOnTheFlyDocsRelevantFileInfoWrapper(c) : null);
+ _wrappedAdditionalContext = _onTheFlyDocsInfo.AdditionalContext.SelectAsArray(c => c is not null ? new CopilotOnTheFlyDocsRelevantFileInfoWrapper(c) : null);
+
+ }
+
+ public string SymbolSignature => _onTheFlyDocsInfo.SymbolSignature;
+ public ImmutableArray DeclarationCode => _wrappedDeclarationCode;
+ public string Language => _onTheFlyDocsInfo.Language;
+ public bool IsContentExcluded => _onTheFlyDocsInfo.IsContentExcluded;
+ public ImmutableArray AdditionalContext => _wrappedAdditionalContext;
+ public bool HasComments => _onTheFlyDocsInfo.HasComments;
+}
+
diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs
new file mode 100644
index 0000000000000..c56903c86cd82
--- /dev/null
+++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/CopilotOnTheFlyDocsRelevantFileInfoWrapper.cs
@@ -0,0 +1,16 @@
+// 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 Microsoft.CodeAnalysis.QuickInfo;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot;
+
+internal sealed class CopilotOnTheFlyDocsRelevantFileInfoWrapper(OnTheFlyDocsRelevantFileInfo onTheFlyDocsRelevantFileInfo)
+{
+ private readonly OnTheFlyDocsRelevantFileInfo _onTheFlyDocsRelevantFileInfo = onTheFlyDocsRelevantFileInfo;
+
+ public Document Document => _onTheFlyDocsRelevantFileInfo.Document;
+ public TextSpan TextSpan => _onTheFlyDocsRelevantFileInfo.TextSpan;
+}
diff --git a/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs
new file mode 100644
index 0000000000000..ba83f33f96137
--- /dev/null
+++ b/src/Features/ExternalAccess/Copilot/OnTheFlyDocs/IExternalCSharpOnTheFlyDocsService.cs
@@ -0,0 +1,15 @@
+// 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;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot
+{
+ internal interface IExternalCSharpOnTheFlyDocsService
+ {
+ Task GetOnTheFlyDocsPromptAsync(CopilotOnTheFlyDocsInfoWrapper onTheFlyDocsInfo, CancellationToken cancellationToken);
+ Task<(string responseString, bool isQuotaExceeded)> GetOnTheFlyDocsResponseAsync(string prompt, CancellationToken cancellationToken);
+ }
+}