-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* bumping nupkgs * Updating to Azure OpenAI v2 Breaking changes in the API * linting * nupkg updates * don't build test project in release mode
- Loading branch information
Showing
23 changed files
with
534 additions
and
532 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project> | ||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<LangVersion>latest</LangVersion> | ||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<RepoRoot>$(MSBuildThisFileDirectory)</RepoRoot> | ||
</PropertyGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,75 @@ | ||
namespace DocGpt | ||
{ | ||
using System.Collections.Immutable; | ||
namespace DocGpt; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
using static Helpers; | ||
using System.Collections.Immutable; | ||
|
||
/// <summary> | ||
/// Represents a diagnostic analyzer for the DocGptAnalyzer class. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class DocGptAnalyzer : DiagnosticAnalyzer | ||
{ | ||
public const string DiagnosticId = "DGPT001"; | ||
using static Helpers; | ||
|
||
// You can change these strings in the AnalyzerResources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. | ||
// See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization | ||
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerTitle), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerMessageFormat), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerDescription), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private const string Category = "Documentation"; | ||
/// <summary> | ||
/// Represents a diagnostic analyzer for the DocGptAnalyzer class. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class DocGptAnalyzer : DiagnosticAnalyzer | ||
{ | ||
public const string DiagnosticId = "DGPT001"; | ||
|
||
internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description); | ||
// You can change these strings in the AnalyzerResources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat. | ||
// See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization | ||
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerTitle), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerMessageFormat), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(AnalyzerResources.AnalyzerDescription), AnalyzerResources.ResourceManager, typeof(AnalyzerResources)); | ||
private const string Category = "Documentation"; | ||
|
||
/// <inheritdoc /> | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); | ||
internal static readonly DiagnosticDescriptor Rule = new(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description); | ||
|
||
/// <inheritdoc /> | ||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
/// <inheritdoc /> | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); | ||
|
||
foreach (SyntaxKind k in DocGptExecutor.SupportedSyntaxes) | ||
{ | ||
context.RegisterSyntaxNodeAction(AnalyzeNode, k); | ||
} | ||
} | ||
/// <inheritdoc /> | ||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
|
||
/// <summary> | ||
/// Analyzes the given syntax node. | ||
/// If XML documentation exists for the node, no diagnostic is reported. | ||
/// If no XML documentation is found, a diagnostic for missing XML documentation is created and reported. | ||
/// </summary> | ||
private void AnalyzeNode(SyntaxNodeAnalysisContext context) | ||
foreach (SyntaxKind k in DocGptExecutor.SupportedSyntaxes) | ||
{ | ||
SyntaxNode node = context.Node; | ||
context.RegisterSyntaxNodeAction(AnalyzeNode, k); | ||
} | ||
} | ||
|
||
if (ShouldSkip(node)) | ||
{ | ||
return; | ||
} | ||
/// <summary> | ||
/// Analyzes the given syntax node. | ||
/// If XML documentation exists for the node, no diagnostic is reported. | ||
/// If no XML documentation is found, a diagnostic for missing XML documentation is created and reported. | ||
/// </summary> | ||
private void AnalyzeNode(SyntaxNodeAnalysisContext context) | ||
{ | ||
SyntaxNode node = context.Node; | ||
|
||
// Create and report the diagnostic | ||
(Location loc, var name) = getLocationAndName(); | ||
var diagnostic = Diagnostic.Create(Rule, loc, node.Kind(), name); | ||
context.ReportDiagnostic(diagnostic); | ||
if (ShouldSkip(node)) | ||
{ | ||
return; | ||
} | ||
|
||
(Location, string) getLocationAndName() | ||
{ | ||
if (node is FieldDeclarationSyntax fs) | ||
{ | ||
SyntaxToken vi = fs.Declaration.Variables.First().Identifier; | ||
return (vi.GetLocation(), vi.ValueText); | ||
} | ||
// Create and report the diagnostic | ||
(Location loc, var name) = getLocationAndName(); | ||
var diagnostic = Diagnostic.Create(Rule, loc, node.Kind(), name); | ||
context.ReportDiagnostic(diagnostic); | ||
|
||
ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(node); | ||
return (symbol.Locations[0], symbol.Name); | ||
(Location, string) getLocationAndName() | ||
{ | ||
if (node is FieldDeclarationSyntax fs) | ||
{ | ||
SyntaxToken vi = fs.Declaration.Variables.First().Identifier; | ||
return (vi.GetLocation(), vi.ValueText); | ||
} | ||
|
||
ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(node); | ||
return (symbol.Locations[0], symbol.Name); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,84 @@ | ||
namespace DocGpt | ||
namespace DocGpt; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
|
||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
using Document = Microsoft.CodeAnalysis.Document; | ||
|
||
/// <summary> | ||
/// This is an internal implementation of CodeAction, that uses OpenAI technology for generating summary text for a member's definition. | ||
/// Preview and Change operations are overridden to add XML documentation to a document at a specified location. This happens asynchronously. | ||
/// </summary> | ||
/// <remarks> | ||
/// Initializes a new instance of the <see cref="DocGptCodeAction"/> class. | ||
/// </remarks> | ||
/// <param name="doc">The document associated with the action.</param> | ||
/// <param name="location">The location within the document where the action is applied.</param> | ||
internal class DocGptCodeAction(Document doc, Location location) : CodeAction | ||
{ | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.Formatting; | ||
/// <inheritdoc /> | ||
public override string EquivalenceKey { get; } = nameof(CodeFixResources.CodeFixTitle); | ||
|
||
using Document = Microsoft.CodeAnalysis.Document; | ||
/// <inheritdoc /> | ||
public override string Title { get; } = CodeFixResources.CodeFixTitle; | ||
|
||
/// <summary> | ||
/// This is an internal implementaion of CodeAction, that uses OpenAI technology for generating summary text for a member's definition. | ||
/// Preview and Change operations are overridden to add XML documentation to a document at a specified location. This happens asynchronously. | ||
/// </summary> | ||
internal class DocGptCodeAction : CodeAction | ||
/// <inheritdoc /> | ||
protected override async Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken) | ||
{ | ||
private readonly Document _doc; | ||
private readonly Location _location; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="DocGptCodeAction"/> class. | ||
/// </summary> | ||
/// <param name="doc">The document associated with the action.</param> | ||
/// <param name="location">The location within the document where the action is applied.</param> | ||
public DocGptCodeAction(Document doc, Location location) | ||
{ | ||
_doc = doc; | ||
_location = location; | ||
} | ||
Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = location.SourceSpan; | ||
SyntaxNode? root = await doc.GetSyntaxRootAsync(cancellationToken); | ||
SyntaxNode? node = root?.FindNode(diagnosticSpan); | ||
|
||
/// <inheritdoc /> | ||
public override string EquivalenceKey { get; } = nameof(CodeFixResources.CodeFixTitle); | ||
|
||
/// <inheritdoc /> | ||
public override string Title { get; } = CodeFixResources.CodeFixTitle; | ||
|
||
/// <inheritdoc /> | ||
protected override async Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken) | ||
{ | ||
Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = _location.SourceSpan; | ||
SyntaxNode root = await _doc.GetSyntaxRootAsync(cancellationToken); | ||
SyntaxNode node = root.FindNode(diagnosticSpan); | ||
return node is not null && DocGptExecutor.NodeTriggersGpt(node) | ||
? DocGptCodeActionPreviewOperation.InstanceArray | ||
: await base.ComputePreviewOperationsAsync(cancellationToken); | ||
} | ||
|
||
return DocGptExecutor.NodeTriggersGpt(node) | ||
? DocGptCodeActionPreviewOperation.InstanceArray | ||
: await base.ComputePreviewOperationsAsync(cancellationToken); | ||
} | ||
/// <inheritdoc /> | ||
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken) | ||
{ | ||
// Find the node at the diagnostic span | ||
Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = location.SourceSpan; | ||
SyntaxNode? root = await doc.GetSyntaxRootAsync(cancellationToken); | ||
SyntaxNode? node = root?.FindNode(diagnosticSpan); | ||
|
||
/// <inheritdoc /> | ||
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken) | ||
if (node is not null) | ||
{ | ||
// Find the node at the diagnostic span | ||
Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = _location.SourceSpan; | ||
SyntaxNode root = await _doc.GetSyntaxRootAsync(cancellationToken); | ||
SyntaxNode node = root.FindNode(diagnosticSpan); | ||
|
||
(SyntaxNode newNode, SyntaxNode nodeToReplace) = await DocGptExecutor.AddXmlDocumentationAsync(node, cancellationToken); | ||
|
||
SyntaxNode newRoot = root.ReplaceNode(nodeToReplace, newNode); | ||
SyntaxNode? newRoot = root?.ReplaceNode(nodeToReplace, newNode); | ||
|
||
// return a document with the new syntax root | ||
return _doc.WithSyntaxRoot(Formatter.Format(newRoot, _doc.Project.Solution.Workspace)); | ||
return newRoot is null ? doc : doc.WithSyntaxRoot(Formatter.Format(newRoot, doc.Project.Solution.Workspace)); | ||
} | ||
|
||
return doc; | ||
} | ||
|
||
/// <summary> | ||
/// Represents an operation that sends the entire member's definition to the defined OpenAI endpoint for summary text generation and applies the result. | ||
/// This operation provides a preview of such operation in its title property. The preview can be asynchronously obtained via GetPreviewAsync method. | ||
/// </summary> | ||
private class DocGptCodeActionPreviewOperation : PreviewOperation | ||
{ | ||
public static readonly DocGptCodeActionPreviewOperation Instance = new(); | ||
public static readonly IEnumerable<CodeActionOperation> InstanceArray = [Instance]; | ||
|
||
/// <summary> | ||
/// Represents an operation that sends the entire member's definition to the defined OpenAI endpoint for summary text generation and applies the result. | ||
/// This operation provides a preview of such operation in its title property. The preview can be asynchronously obtained via GetPreviewAsync method. | ||
/// Initializes a new instance of the DocGptCodeActionPreviewOperation class. | ||
/// </summary> | ||
private class DocGptCodeActionPreviewOperation : PreviewOperation | ||
{ | ||
public static readonly DocGptCodeActionPreviewOperation Instance = new DocGptCodeActionPreviewOperation(); | ||
public static readonly IEnumerable<CodeActionOperation> InstanceArray = new CodeActionOperation[] { Instance }; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the DocGptCodeActionPreviewOperation class. | ||
/// </summary> | ||
private DocGptCodeActionPreviewOperation() { } | ||
private DocGptCodeActionPreviewOperation() { } | ||
|
||
/// <inheritdoc /> | ||
public override string Title { get; } = "Sends this entire member's definition (and body) to the defined OpenAI endpoint for summary text generation and applies the result."; | ||
/// <inheritdoc /> | ||
public override string Title { get; } = "Sends this entire member's definition (and body) to the defined OpenAI endpoint for summary text generation and applies the result."; | ||
|
||
/// <inheritdoc /> | ||
public override Task<object> GetPreviewAsync(CancellationToken cancellationToken) => Task.FromResult<object>(this.Title); | ||
} | ||
/// <inheritdoc /> | ||
public override Task<object?> GetPreviewAsync(CancellationToken cancellationToken) => Task.FromResult<object?>(this.Title); | ||
} | ||
} |
Oops, something went wrong.