From 46ca68f928425654ac32359382ccc6d151553bb7 Mon Sep 17 00:00:00 2001 From: Brandon H Date: Thu, 12 Dec 2024 19:54:00 -0800 Subject: [PATCH] Pkg updates (#18) * bumping nupkgs * Updating to Azure OpenAI v2 Breaking changes in the API * linting * nupkg updates * don't build test project in release mode --- Directory.Build.props | 13 + DocGpt.Roslyn/DocGpt.Roslyn.csproj | 4 +- DocGpt.Roslyn/DocGptAnalyzer.cs | 115 ++++---- DocGpt.Roslyn/DocGptCodeAction.cs | 130 +++++---- DocGpt.Roslyn/DocGptCodeFixProvider.cs | 103 ++++--- DocGpt.Roslyn/DocGptExecutor.cs | 253 +++++++++--------- DocGpt.Roslyn/DocGptRefactoringProvider.cs | 71 +++-- DocGpt.Roslyn/Helpers.cs | 113 ++++---- DocGpt.Roslyn/Options/DocGptOptions.cs | 145 +++++----- DocGpt.Roslyn/Options/OverrideBehavior.cs | 19 +- DocGpt.Test/AnalyzerTests.cs | 4 +- DocGpt.Test/CodeFixTests.cs | 11 +- DocGpt.Test/DocGpt.Test.csproj | 17 +- DocGpt.Test/GptSetup.cs | 4 +- DocGpt.Test/RefactoringTests.cs | 4 +- .../Verifiers/CSharpAnalyzerVerifier`1.cs | 6 +- .../Verifiers/CSharpCodeFixVerifier`2.cs | 6 +- .../CSharpCodeRefactoringVerifier`1.cs | 6 +- DocGpt.Test/Verifiers/CSharpVerifierHelper.cs | 6 +- DocGpt.Vsix/DocGpt.Vsix.csproj | 20 +- DocGpt.Vsix/DocGptOptionsPage.cs | 8 +- DocGpt.Vsix/DocGptPackage.cs | 6 +- DocGpt.sln | 2 +- 23 files changed, 534 insertions(+), 532 deletions(-) create mode 100644 Directory.Build.props diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..b9ff5d5 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,13 @@ + + + net8.0 + enable + enable + latest + Linux + + + + $(MSBuildThisFileDirectory) + + \ No newline at end of file diff --git a/DocGpt.Roslyn/DocGpt.Roslyn.csproj b/DocGpt.Roslyn/DocGpt.Roslyn.csproj index 37957d7..1138d3e 100644 --- a/DocGpt.Roslyn/DocGpt.Roslyn.csproj +++ b/DocGpt.Roslyn/DocGpt.Roslyn.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/DocGpt.Roslyn/DocGptAnalyzer.cs b/DocGpt.Roslyn/DocGptAnalyzer.cs index 85eb0f4..302e7ce 100644 --- a/DocGpt.Roslyn/DocGptAnalyzer.cs +++ b/DocGpt.Roslyn/DocGptAnalyzer.cs @@ -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; - /// - /// Represents a diagnostic analyzer for the DocGptAnalyzer class. - /// - [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"; +/// +/// Represents a diagnostic analyzer for the DocGptAnalyzer class. +/// +[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"; - /// - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + internal static readonly DiagnosticDescriptor Rule = new(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Info, isEnabledByDefault: true, description: Description); - /// - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); - context.EnableConcurrentExecution(); + /// + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); - foreach (SyntaxKind k in DocGptExecutor.SupportedSyntaxes) - { - context.RegisterSyntaxNodeAction(AnalyzeNode, k); - } - } + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); - /// - /// 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. - /// - private void AnalyzeNode(SyntaxNodeAnalysisContext context) + foreach (SyntaxKind k in DocGptExecutor.SupportedSyntaxes) { - SyntaxNode node = context.Node; + context.RegisterSyntaxNodeAction(AnalyzeNode, k); + } + } - if (ShouldSkip(node)) - { - return; - } + /// + /// 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. + /// + 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); } } } diff --git a/DocGpt.Roslyn/DocGptCodeAction.cs b/DocGpt.Roslyn/DocGptCodeAction.cs index 1fb4978..92c1ddd 100644 --- a/DocGpt.Roslyn/DocGptCodeAction.cs +++ b/DocGpt.Roslyn/DocGptCodeAction.cs @@ -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; + +/// +/// 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. +/// +/// +/// Initializes a new instance of the class. +/// +/// The document associated with the action. +/// The location within the document where the action is applied. +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; + /// + public override string EquivalenceKey { get; } = nameof(CodeFixResources.CodeFixTitle); - using Document = Microsoft.CodeAnalysis.Document; + /// + public override string Title { get; } = CodeFixResources.CodeFixTitle; - /// - /// 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. - /// - internal class DocGptCodeAction : CodeAction + /// + protected override async Task> ComputePreviewOperationsAsync(CancellationToken cancellationToken) { - private readonly Document _doc; - private readonly Location _location; - - /// - /// Initializes a new instance of the class. - /// - /// The document associated with the action. - /// The location within the document where the action is applied. - 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); - /// - public override string EquivalenceKey { get; } = nameof(CodeFixResources.CodeFixTitle); - - /// - public override string Title { get; } = CodeFixResources.CodeFixTitle; - - /// - protected override async Task> 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); - } + /// + protected override async Task 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); - /// - protected override async Task 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; + } + + /// + /// 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. + /// + private class DocGptCodeActionPreviewOperation : PreviewOperation + { + public static readonly DocGptCodeActionPreviewOperation Instance = new(); + public static readonly IEnumerable InstanceArray = [Instance]; + /// - /// 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. /// - private class DocGptCodeActionPreviewOperation : PreviewOperation - { - public static readonly DocGptCodeActionPreviewOperation Instance = new DocGptCodeActionPreviewOperation(); - public static readonly IEnumerable InstanceArray = new CodeActionOperation[] { Instance }; - - /// - /// Initializes a new instance of the DocGptCodeActionPreviewOperation class. - /// - private DocGptCodeActionPreviewOperation() { } + private DocGptCodeActionPreviewOperation() { } - /// - 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."; + /// + 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."; - /// - public override Task GetPreviewAsync(CancellationToken cancellationToken) => Task.FromResult(this.Title); - } + /// + public override Task GetPreviewAsync(CancellationToken cancellationToken) => Task.FromResult(this.Title); } } diff --git a/DocGpt.Roslyn/DocGptCodeFixProvider.cs b/DocGpt.Roslyn/DocGptCodeFixProvider.cs index 7e2a1ab..680cd0d 100644 --- a/DocGpt.Roslyn/DocGptCodeFixProvider.cs +++ b/DocGpt.Roslyn/DocGptCodeFixProvider.cs @@ -1,69 +1,68 @@ -namespace DocGpt +namespace DocGpt; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading.Tasks; + +/// +/// The doc gpt code fix provider. +/// +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DocGptCodeFixProvider)), Shared] +public class DocGptCodeFixProvider : CodeFixProvider { - using System.Collections.Immutable; - using System.Composition; - using System.Linq; - using System.Threading.Tasks; + /// + /// Gets the fixable diagnostic ids. + /// + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create("CS1591", // The diagnostic id of the XML Documentation an analyzer fired when XML doc gen is turned on but missing from a visible member + "CD1606", // Diagnostic from "CodeDocumentor" analyzer (https://marketplace.visualstudio.com/items?itemName=DanTurco.CodeDocumentor) + DocGptAnalyzer.DiagnosticId); - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CodeFixes; - using Microsoft.CodeAnalysis.CSharp.Syntax; + /// + /// Get the fix all provider. + /// + /// A FixAllProvider. + public sealed override FixAllProvider GetFixAllProvider() => + // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers + WellKnownFixAllProviders.BatchFixer; /// - /// The doc gpt code fix provider. + /// Registers the code fixes asynchronously. /// - [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DocGptCodeFixProvider)), Shared] - public class DocGptCodeFixProvider : CodeFixProvider + /// The context. + /// A Task. + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - /// - /// Gets the fixable diagnostic ids. - /// - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create("CS1591", // The diagnostic id of the XML Documentation an analyzer fired when XML doc gen is turned on but missing from a visible member - "CD1606", // Diagnostic from "CodeDocumentor" analyzer (https://marketplace.visualstudio.com/items?itemName=DanTurco.CodeDocumentor) - DocGptAnalyzer.DiagnosticId); + SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - /// - /// Get the fix all provider. - /// - /// A FixAllProvider. - public sealed override FixAllProvider GetFixAllProvider() => - // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/FixAllProvider.md for more information on Fix All Providers - WellKnownFixAllProviders.BatchFixer; - - /// - /// Registers the code fixes asynchronously. - /// - /// The context. - /// A Task. - public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) + Diagnostic diagnostic = context.Diagnostics.FirstOrDefault(i => this.FixableDiagnosticIds.Contains(i.Id)); + if (diagnostic is null) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + return; + } - Diagnostic diagnostic = context.Diagnostics.FirstOrDefault(i => this.FixableDiagnosticIds.Contains(i.Id)); - if (diagnostic is null) + Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; + + SyntaxNode node = root.FindNode(diagnosticSpan); + if (node is VariableDeclaratorSyntax v) + { + if (node.Parent?.Parent is FieldDeclarationSyntax f) { - return; + node = f; } - - Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; - - SyntaxNode node = root.FindNode(diagnosticSpan); - if (node is VariableDeclaratorSyntax v) + else { - if (node.Parent?.Parent is FieldDeclarationSyntax f) - { - node = f; - } - else - { - return; - } + return; } + } - var code = root.GetText().GetSubText(diagnosticSpan).ToString(); + var code = root.GetText().GetSubText(diagnosticSpan).ToString(); - // Register a code action that will invoke the fix. - context.RegisterCodeFix(new DocGptCodeAction(context.Document, diagnostic.Location), diagnostic); - } + // Register a code action that will invoke the fix. + context.RegisterCodeFix(new DocGptCodeAction(context.Document, diagnostic.Location), diagnostic); } } diff --git a/DocGpt.Roslyn/DocGptExecutor.cs b/DocGpt.Roslyn/DocGptExecutor.cs index bdc2c44..138e68c 100644 --- a/DocGpt.Roslyn/DocGptExecutor.cs +++ b/DocGpt.Roslyn/DocGptExecutor.cs @@ -1,76 +1,73 @@ -namespace DocGpt -{ - using System; - using System.Text.RegularExpressions; - using System.Threading; - using System.Threading.Tasks; +namespace DocGpt; + +using DocGpt.Options; - using Azure.AI.OpenAI; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; - using DocGpt.Options; +using OpenAI.Chat; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; - using static Helpers; +using static Helpers; + +/// +/// An internal static class which hosts methods to add XML documentation to a provided Document using GPT service. +/// +internal static class DocGptExecutor +{ + public static readonly SyntaxKind[] SupportedSyntaxes = [ + SyntaxKind.ClassDeclaration, + SyntaxKind.StructDeclaration, + SyntaxKind.InterfaceDeclaration, + SyntaxKind.EnumDeclaration, + SyntaxKind.DelegateDeclaration, + SyntaxKind.FieldDeclaration, + SyntaxKind.PropertyDeclaration, + SyntaxKind.EventDeclaration, + SyntaxKind.MethodDeclaration, + SyntaxKind.ConstructorDeclaration, + SyntaxKind.IndexerDeclaration, + SyntaxKind.RecordDeclaration, + SyntaxKind.RecordStructDeclaration, + SyntaxKind.EnumMemberDeclaration, + // Add other member types if needed + ]; /// - /// An internal static class which hosts methods to add XML documentation to a provided Document using GPT service. + /// Asynchronously adds XML documentation to a given document based on a provided diagnostic, using GPT for generating the documentation. /// - internal static class DocGptExecutor + /// The node to add XML documentation to. + /// A cancellation token for the operation. + /// A Task returning a Document with the new XML documentation added. + public static async Task<(SyntaxNode newNode, SyntaxNode nodeToReplace)> AddXmlDocumentationAsync(SyntaxNode node, CancellationToken cancellationToken) { - public static readonly SyntaxKind[] SupportedSyntaxes = new[] { - SyntaxKind.ClassDeclaration, - SyntaxKind.StructDeclaration, - SyntaxKind.InterfaceDeclaration, - SyntaxKind.EnumDeclaration, - SyntaxKind.DelegateDeclaration, - SyntaxKind.FieldDeclaration, - SyntaxKind.PropertyDeclaration, - SyntaxKind.EventDeclaration, - SyntaxKind.MethodDeclaration, - SyntaxKind.ConstructorDeclaration, - SyntaxKind.IndexerDeclaration, - SyntaxKind.RecordDeclaration, - SyntaxKind.RecordStructDeclaration, - SyntaxKind.EnumMemberDeclaration, - // Add other member types if needed - }; - - /// - /// Asynchronously adds XML documentation to a given document based on a provided diagnostic, using GPT for generating the documentation. - /// - /// The node to add XML documentation to. - /// A cancellation token for the operation. - /// A Task returning a Document with the new XML documentation added. - public static async Task<(SyntaxNode newNode, SyntaxNode nodeToReplace)> AddXmlDocumentationAsync(SyntaxNode node, CancellationToken cancellationToken) + _ = node ?? throw new ArgumentNullException(nameof(node)); + + if (HasOverrideModifier(node) && DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.UseInheritDoc) { - _ = node ?? throw new ArgumentNullException(nameof(node)); + return (DecorateWithInheritDoc(node), node); + } - if (HasOverrideModifier(node) && DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.UseInheritDoc) - { - return (DecorateWithInheritDoc(node), node); - } + if (IsConstantLiteral(node, out Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax parentField) && DocGptOptions.Instance.UseValueForLiteralConstants is true) + { + return (DecorateWithValueAsSummary(parentField), parentField); + } - if (IsConstantLiteral(node, out Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax parentField) && DocGptOptions.Instance.UseValueForLiteralConstants is true) - { - return (DecorateWithValueAsSummary(parentField), parentField); - } + // Get the body of the method + var code = node.GetText().ToString(); - // Get the body of the method - var code = node.GetText().ToString(); + try + { + var client = DocGptOptions.Instance.GetClient(); try { - OpenAIClient client = DocGptOptions.Instance.GetClient(); - - var completionOptions = new ChatCompletionsOptions(); - if (!string.IsNullOrWhiteSpace(DocGptOptions.Instance.ModelDeploymentName)) - { - completionOptions.DeploymentName = DocGptOptions.Instance.ModelDeploymentName; - } - - completionOptions.Messages.Add(new ChatRequestUserMessage($@"You are to take the C# code below and create a valid XML Documentation summary block for it according to .NET specifications. Use the following steps to determine what you compute for the answer: + var completion = await client.CompleteChatAsync([ + new UserChatMessage($@"You are to take the C# code below and create a valid XML Documentation summary block for it according to .NET specifications. Use the following steps to determine what you compute for the answer: 1. If the given code is not a complete C# type or member declaration, stop computing and return nothing. 2. If the declaration is a variable or field, your summary should attempt to discern what the variable may mean based on its name and - if assigned - its value. Don't include the ""gets or sets"" verbiage. @@ -80,101 +77,97 @@ internal static class DocGptExecutor {code} ``` -You are to give back only the XML documentation wrapped in a code block (```), do not respond with any other text.")); +You are to give back only the XML documentation wrapped in a code block (```), do not respond with any other text.") + ], cancellationToken: cancellationToken); + var comment = completion.Value.Content[0].Text; + ExtractXmlDocComment(ref comment); - try + SyntaxTriviaList commentTrivia = CreateTrivia(node, comment); + // Add the comment to the start of the node found by the analyzer + return (node.WithLeadingTrivia(commentTrivia), node); + } + catch (Exception e) + { + if (e is not TaskCanceledException and not OperationCanceledException) { - Azure.Response completion = await client.GetChatCompletionsAsync(completionOptions, cancellationToken); - var comment = completion.Value.Choices[0].Message.Content; - ExtractXmlDocComment(ref comment); - - SyntaxTriviaList commentTrivia = CreateTrivia(node, comment); - // Add the comment to the start of the node found by the analyzer - return (node.WithLeadingTrivia(commentTrivia), node); + System.Diagnostics.Debugger.Break(); } - catch (Exception e) - { - if (!(e is TaskCanceledException) && !(e is OperationCanceledException)) - { - System.Diagnostics.Debugger.Break(); - } - throw; - } - } - catch (ArgumentNullException e) - { - return (node.WithLeadingTrivia(SyntaxFactory.Comment($"// Missing {e.ParamName} - Make sure you've entered the necessary information in Tools | Options | Doc GPT and try again.\r\n")), node); + throw; } } + catch (ArgumentNullException e) + { + return (node.WithLeadingTrivia(SyntaxFactory.Comment($"// Missing {e.ParamName} - Make sure you've entered the necessary information in Tools | Options | Doc GPT and try again.\r\n")), node); + } + } - private static readonly Regex _lineFeedRegex = new Regex("(? 0) - { - if (numCrLfs is 0) - { - // if the node has only line feeds, make sure the comment ends in line feeds - comment = _crlfRegex.Replace(comment, "\n"); - } + private static SyntaxTriviaList CreateTrivia(SyntaxNode node, string comment) + { + // If the node's line endings are all crlf, make sure GPT's generated output ends in crlf as well + var nodeCurrentText = node.GetText().ToString(); + var numLineFeeds = _lineFeedRegex.Matches(nodeCurrentText).Count; + var numCrLfs = _crlfRegex.Matches(nodeCurrentText).Count; - // If the node already has mixed endings, don't do anything - } - else if (numCrLfs > 0) + if (numLineFeeds > 0) + { + if (numCrLfs is 0) { - // if the node has only crlfs, make sure the comment ends in crlfs - comment = _lineFeedRegex.Replace(comment, "\r\n"); + // if the node has only line feeds, make sure the comment ends in line feeds + comment = _crlfRegex.Replace(comment, "\n"); } - return SyntaxFactory.ParseLeadingTrivia(comment).InsertRange(0, node.GetLeadingTrivia()); + // If the node already has mixed endings, don't do anything } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Readability")] - internal static bool NodeTriggersGpt(SyntaxNode node) + else if (numCrLfs > 0) { - if (HasOverrideModifier(node)) - { - return DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.GptSummarize; - } + // if the node has only crlfs, make sure the comment ends in crlfs + comment = _lineFeedRegex.Replace(comment, "\r\n"); + } - if (IsConstantLiteral(node, out _)) - { - return !(DocGptOptions.Instance.UseValueForLiteralConstants is true); - } + return SyntaxFactory.ParseLeadingTrivia(comment).InsertRange(0, node.GetLeadingTrivia()); + } - return true; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Readability")] + internal static bool NodeTriggersGpt(SyntaxNode node) + { + if (HasOverrideModifier(node)) + { + return DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.GptSummarize; } - /// - /// Extracts an XML comment from a given string, trimming any markdown code block symbols or language specifiers. - /// - /// The string containing the XML comment to be extracted. This string is modified by this method. - private static void ExtractXmlDocComment(ref string comment) + if (IsConstantLiteral(node, out _)) { - // if the comment is surrounded by code block markdown, remove it and any language specifier - var codeBlockLocation = comment.IndexOf("```", StringComparison.Ordinal); - if (codeBlockLocation >= 0) - { - comment = comment.Substring(codeBlockLocation + 3); + return DocGptOptions.Instance.UseValueForLiteralConstants is not true; + } - var idx = comment.IndexOf('\n'); - if (idx > 0) - { - comment = comment.Substring(idx + 1); - } + return true; + } + + /// + /// Extracts an XML comment from a given string, trimming any markdown code block symbols or language specifiers. + /// + /// The string containing the XML comment to be extracted. This string is modified by this method. + private static void ExtractXmlDocComment(ref string comment) + { + // if the comment is surrounded by code block markdown, remove it and any language specifier + var codeBlockLocation = comment.IndexOf("```", StringComparison.Ordinal); + if (codeBlockLocation >= 0) + { + comment = comment.Substring(codeBlockLocation + 3); + + var idx = comment.IndexOf('\n'); + if (idx > 0) + { + comment = comment.Substring(idx + 1); } + } - comment = $@"{comment.TrimStart().TrimEnd().TrimEnd('`', '\n', '\r')} + comment = $@"{comment.TrimStart().TrimEnd().TrimEnd('`', '\n', '\r')} "; - } } } diff --git a/DocGpt.Roslyn/DocGptRefactoringProvider.cs b/DocGpt.Roslyn/DocGptRefactoringProvider.cs index 91a446a..3d106fc 100644 --- a/DocGpt.Roslyn/DocGptRefactoringProvider.cs +++ b/DocGpt.Roslyn/DocGptRefactoringProvider.cs @@ -1,46 +1,45 @@ -namespace DocGpt -{ - using System; - using System.Composition; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; +namespace DocGpt; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CodeRefactorings; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; - /// - /// The doc gpt code fix provider. - /// - [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(DocGptRefactoringProvider)), Shared] - public class DocGptRefactoringProvider : CodeRefactoringProvider +/// +/// The doc gpt code fix provider. +/// +[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(DocGptRefactoringProvider)), Shared] +public class DocGptRefactoringProvider : CodeRefactoringProvider +{ + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { - public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) - { - Document document = context.Document; - Microsoft.CodeAnalysis.Text.TextSpan textSpan = context.Span; - CancellationToken cancellationToken = context.CancellationToken; + Document document = context.Document; + Microsoft.CodeAnalysis.Text.TextSpan textSpan = context.Span; + CancellationToken cancellationToken = context.CancellationToken; - SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - // Find the node at the selection. - SyntaxNode node = root.FindNode(textSpan); - if (!DocGptExecutor.SupportedSyntaxes.Contains(node.Kind())) + // Find the node at the selection. + SyntaxNode node = root.FindNode(textSpan); + if (!DocGptExecutor.SupportedSyntaxes.Contains(node.Kind())) + { + if (node.Parent?.Parent is FieldDeclarationSyntax) { - if (node.Parent?.Parent is FieldDeclarationSyntax) - { - node = node.Parent.Parent; - } - else - { - return; - } + node = node.Parent.Parent; + } + else + { + return; } - - // Register a code action that will invoke the fix. - context.RegisterRefactoring(new DocGptCodeAction(context.Document, node.GetLocation())); } + + // Register a code action that will invoke the fix. + context.RegisterRefactoring(new DocGptCodeAction(context.Document, node.GetLocation())); } } diff --git a/DocGpt.Roslyn/Helpers.cs b/DocGpt.Roslyn/Helpers.cs index 717030b..01f58c4 100644 --- a/DocGpt.Roslyn/Helpers.cs +++ b/DocGpt.Roslyn/Helpers.cs @@ -1,82 +1,81 @@ -namespace DocGpt -{ - using System.Linq; +namespace DocGpt; - using DocGpt.Options; +using DocGpt.Options; - using Microsoft.CodeAnalysis; - using Microsoft.CodeAnalysis.CSharp; - using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; - internal static class Helpers - { - public static bool HasOverrideModifier(SyntaxNode node) => node is MemberDeclarationSyntax m && m.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.OverrideKeyword)); +using System.Linq; - public static SyntaxNode DecorateWithInheritDoc(SyntaxNode node) => DecorateWithXmlDocumentation(node, @"/// "); +internal static class Helpers +{ + public static bool HasOverrideModifier(SyntaxNode node) => node is MemberDeclarationSyntax m && m.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.OverrideKeyword)); - public static SyntaxNode DecorateWithValueAsSummary(FieldDeclarationSyntax node) => DecorateWithXmlDocumentation(node, $"/// {node.Declaration.Variables[0].Initializer.Value.ChildTokens().First().ValueText}"); + public static SyntaxNode DecorateWithInheritDoc(SyntaxNode node) => DecorateWithXmlDocumentation(node, @"/// "); - public static SyntaxNode DecorateWithXmlDocumentation(SyntaxNode node, string documentationContent) - { - SyntaxTriviaList commentTrivia = SyntaxFactory.ParseLeadingTrivia($@"{documentationContent} + public static SyntaxNode DecorateWithValueAsSummary(FieldDeclarationSyntax node) => DecorateWithXmlDocumentation(node, $"/// {node.Declaration.Variables[0].Initializer.Value.ChildTokens().First().ValueText}"); + + public static SyntaxNode DecorateWithXmlDocumentation(SyntaxNode node, string documentationContent) + { + SyntaxTriviaList commentTrivia = SyntaxFactory.ParseLeadingTrivia($@"{documentationContent} ").InsertRange(0, node.GetLeadingTrivia()); - return node.WithLeadingTrivia(commentTrivia); - } + return node.WithLeadingTrivia(commentTrivia); + } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Readability")] - public static bool ShouldSkip(SyntaxNode node) + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Readability")] + public static bool ShouldSkip(SyntaxNode node) + { + // Skip nodes that already have XML documentation + if (node.HasLeadingTrivia) { - // Skip nodes that already have XML documentation - if (node.HasLeadingTrivia) + // Go through each piece of trivia leading the node + foreach (SyntaxTrivia trivia in node.GetLeadingTrivia()) { - // Go through each piece of trivia leading the node - foreach (SyntaxTrivia trivia in node.GetLeadingTrivia()) + // Check if the trivia is of kind 'DocumentationCommentTrivia' + if (trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || + trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)) { - // Check if the trivia is of kind 'DocumentationCommentTrivia' - if (trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || - trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)) - { - // XML documentation exists, so return without reporting a diagnostic - return true; - } + // XML documentation exists, so return without reporting a diagnostic + return true; } } + } - // Skip overrides if user has elected not to document them - if (IsOverriddenMember(node)) - { - return DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.DoNotDocument; - } - - // Skip field declarations that are not constants with a literal expression, - // or if user has set the option to not document these. - if (IsConstantLiteral(node, out _)) - { - return !DocGptOptions.Instance.UseValueForLiteralConstants; - } + // Skip overrides if user has elected not to document them + if (IsOverriddenMember(node)) + { + return DocGptOptions.Instance.OverridesBehavior is OverrideBehavior.DoNotDocument; + } - return node is VariableDeclarationSyntax; + // Skip field declarations that are not constants with a literal expression, + // or if user has set the option to not document these. + if (IsConstantLiteral(node, out _)) + { + return !DocGptOptions.Instance.UseValueForLiteralConstants; } - public static bool IsOverriddenMember(SyntaxNode node) => node is MemberDeclarationSyntax m && m.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.OverrideKeyword)); + return node is VariableDeclarationSyntax; + } - public static bool IsConstantLiteral(SyntaxNode node, out FieldDeclarationSyntax parentField) - { - parentField = null; + public static bool IsOverriddenMember(SyntaxNode node) => node is MemberDeclarationSyntax m && m.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.OverrideKeyword)); + + public static bool IsConstantLiteral(SyntaxNode node, out FieldDeclarationSyntax parentField) + { + parentField = null; - if (node is VariableDeclaratorSyntax - && node.Parent?.Parent is FieldDeclarationSyntax field) + if (node is VariableDeclaratorSyntax + && node.Parent?.Parent is FieldDeclarationSyntax field) + { + parentField = field; + if (field?.Modifiers.Any(SyntaxKind.ConstKeyword) is true + && field.Declaration.Variables.FirstOrDefault()?.Initializer?.Value is LiteralExpressionSyntax) { - parentField = field; - if (field?.Modifiers.Any(SyntaxKind.ConstKeyword) is true - && field.Declaration.Variables.FirstOrDefault()?.Initializer?.Value is LiteralExpressionSyntax) - { - return true; - } + return true; } - - return false; } + + return false; } } diff --git a/DocGpt.Roslyn/Options/DocGptOptions.cs b/DocGpt.Roslyn/Options/DocGptOptions.cs index aacaa59..ab9e365 100644 --- a/DocGpt.Roslyn/Options/DocGptOptions.cs +++ b/DocGpt.Roslyn/Options/DocGptOptions.cs @@ -1,88 +1,97 @@ -namespace DocGpt.Options -{ - using System; +namespace DocGpt.Options; + +using Azure.AI.OpenAI; - using Azure.AI.OpenAI; +using OpenAI; +using OpenAI.Chat; +using System; +using System.ClientModel; + +/// +/// Represents the configuration options for an OpenAI or Azure-based OpenAI service. +/// This includes properties required for connection such as the endpoint URL and API key. +/// It also includes the name of the model or deployment to use. +/// +public sealed class DocGptOptions +{ + public static readonly DocGptOptions Instance = new(); /// - /// Represents the configuration options for an OpenAI or Azure-based OpenAI service. - /// This includes properties required for connection such as the endpoint URL and API key. - /// It also includes the name of the model or deployment to use. + /// Initializes a new instance of the class. /// - public sealed class DocGptOptions - { - public static readonly DocGptOptions Instance = new DocGptOptions(); - /// - /// Initializes a new instance of the class. - /// - private DocGptOptions() { } + private DocGptOptions() { } - /// - /// Gets or Sets the endpoint. - /// - public Uri Endpoint + /// + /// Gets or Sets the endpoint. + /// + public Uri Endpoint + { + get => _endpoint; + set { - get => _endpoint; - set - { - _endpoint = value; - _client = null; - } + _endpoint = value; + _client = null; } + } - /// - /// Gets or sets the OpenAI or Azure OpenAI API key. Changing the value of this property will reset the underlying client. - /// - /// - /// The API key. - /// - public string ApiKey + /// + /// Gets or sets the OpenAI or Azure OpenAI API key. Changing the value of this property will reset the underlying client. + /// + /// + /// The API key. + /// + public string ApiKey + { + get => _apiKey ?? string.Empty; + set { - get => _apiKey; - set - { - _apiKey = value; - _client = null; - } + _apiKey = value; + _client = null; } + } - /// - /// Gets or sets the OpenAI or Azure OpenAI API model or deployment name. - /// - /// - /// The OpenAI or Azure OpenAI API model or deployment name. - /// - public string ModelDeploymentName { get; set; } + /// + /// Gets or sets the OpenAI model or Azure OpenAI deployment name. + /// + /// + /// The OpenAI model or Azure OpenAI deployment name. + /// + public string? ModelDeploymentName { get; set; } - private OpenAIClient _client; - private string _apiKey; - private Uri _endpoint = new Uri("https://api.openai.com"); + private ChatClient? _client; + private string? _apiKey; + private Uri _endpoint = new("https://api.openai.com"); - /// - /// Gets an instance of the OpenAIClient. If the client instance is null, it creates a new instance - /// based on whether the host endpoint ends with "azure.com" or not, using the provided API key. - /// - public OpenAIClient GetClient() + /// + /// Gets an instance of the OpenAIClient. If the client instance is null, it creates a new instance + /// based on whether the host endpoint ends with "azure.com" or not, using the provided API key. + /// + public ChatClient GetClient() + { + if (string.IsNullOrWhiteSpace(this.ModelDeploymentName)) { - if (_client is null) - { - _client = - _endpoint.Host.EndsWith("azure.com", StringComparison.OrdinalIgnoreCase) - ? new OpenAIClient(_endpoint ?? throw new ArgumentNullException(nameof(this.Endpoint)), new Azure.AzureKeyCredential(_apiKey ?? throw new ArgumentNullException(nameof(this.ApiKey)))) - : new OpenAIClient(_apiKey ?? throw new ArgumentNullException(nameof(this.ApiKey))); - } + throw new ArgumentNullException(nameof(this.ModelDeploymentName)); + } - return _client; + if (string.IsNullOrWhiteSpace(_apiKey)) + { + throw new ArgumentNullException(nameof(this.ApiKey)); } - /// - /// Gets or Sets whether/not to add tags to overridden members. - /// - public OverrideBehavior OverridesBehavior { get; set; } = OverrideBehavior.UseInheritDoc; + _client ??= _endpoint.Host.EndsWith("azure.com", StringComparison.OrdinalIgnoreCase) + ? new AzureOpenAIClient(_endpoint ?? throw new ArgumentNullException(nameof(this.Endpoint)), new ApiKeyCredential(_apiKey!)).GetChatClient(this.ModelDeploymentName) + : new OpenAIClient(_apiKey).GetChatClient(this.ModelDeploymentName); - /// - /// Gets or Sets whether/not to add {value} on literal constants. - /// - public bool UseValueForLiteralConstants { get; set; } = true; + return _client; } + + /// + /// Gets or Sets whether/not to add tags to overridden members. + /// + public OverrideBehavior OverridesBehavior { get; set; } = OverrideBehavior.UseInheritDoc; + + /// + /// Gets or Sets whether/not to add {value} on literal constants. + /// + public bool UseValueForLiteralConstants { get; set; } = true; } diff --git a/DocGpt.Roslyn/Options/OverrideBehavior.cs b/DocGpt.Roslyn/Options/OverrideBehavior.cs index a732ed2..68a8a7e 100644 --- a/DocGpt.Roslyn/Options/OverrideBehavior.cs +++ b/DocGpt.Roslyn/Options/OverrideBehavior.cs @@ -1,15 +1,14 @@ -namespace DocGpt.Options +namespace DocGpt.Options; + +/// +public enum OverrideBehavior { /// - public enum OverrideBehavior - { - /// - DoNotDocument, + DoNotDocument, - /// - UseInheritDoc, + /// + UseInheritDoc, - /// - GptSummarize - } + /// + GptSummarize } diff --git a/DocGpt.Test/AnalyzerTests.cs b/DocGpt.Test/AnalyzerTests.cs index a679679..b6e71bd 100644 --- a/DocGpt.Test/AnalyzerTests.cs +++ b/DocGpt.Test/AnalyzerTests.cs @@ -1,12 +1,12 @@ namespace DocGpt.Test; -using System.Threading.Tasks; - using DocGpt.Options; using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; + using VerifyCS = CSharpAnalyzerVerifier; /// diff --git a/DocGpt.Test/CodeFixTests.cs b/DocGpt.Test/CodeFixTests.cs index 6cf7249..6e2ff34 100644 --- a/DocGpt.Test/CodeFixTests.cs +++ b/DocGpt.Test/CodeFixTests.cs @@ -1,10 +1,4 @@ namespace DocGpt.Test; - -using System.Net.Http.Headers; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - using DocGpt.Options; using Microsoft.CodeAnalysis; @@ -12,6 +6,9 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + using VerifyCS = CSharpCodeFixVerifier; /// @@ -20,7 +17,7 @@ [TestClass] public partial class CodeFixTests { - public TestContext TestContext { get; set; } + public required TestContext TestContext { get; set; } /// /// Analyzers the throws class decl. diff --git a/DocGpt.Test/DocGpt.Test.csproj b/DocGpt.Test/DocGpt.Test.csproj index 06142af..564194a 100644 --- a/DocGpt.Test/DocGpt.Test.csproj +++ b/DocGpt.Test/DocGpt.Test.csproj @@ -1,20 +1,19 @@  - net8.0 - true true - - - - - - - + + + + + + + + diff --git a/DocGpt.Test/GptSetup.cs b/DocGpt.Test/GptSetup.cs index cb668fe..59418fa 100644 --- a/DocGpt.Test/GptSetup.cs +++ b/DocGpt.Test/GptSetup.cs @@ -1,7 +1,5 @@ namespace DocGpt.Test; -using System.Threading.Tasks; - using Azure; using DocGpt.Options; @@ -11,6 +9,8 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; + [TestClass] internal static class GptSetup { diff --git a/DocGpt.Test/RefactoringTests.cs b/DocGpt.Test/RefactoringTests.cs index 876dee5..84c5268 100644 --- a/DocGpt.Test/RefactoringTests.cs +++ b/DocGpt.Test/RefactoringTests.cs @@ -1,9 +1,9 @@ namespace DocGpt.Test; -using System.Threading.Tasks; - using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; + using RefactorCS = CSharpCodeRefactoringVerifier; [TestClass] diff --git a/DocGpt.Test/Verifiers/CSharpAnalyzerVerifier`1.cs b/DocGpt.Test/Verifiers/CSharpAnalyzerVerifier`1.cs index 881fd06..6d7dcd8 100644 --- a/DocGpt.Test/Verifiers/CSharpAnalyzerVerifier`1.cs +++ b/DocGpt.Test/Verifiers/CSharpAnalyzerVerifier`1.cs @@ -1,14 +1,14 @@ namespace DocGpt.Test; -using System.Threading; -using System.Threading.Tasks; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Testing.Verifiers; +using System.Threading; +using System.Threading.Tasks; + public static partial class CSharpAnalyzerVerifier where TAnalyzer : DiagnosticAnalyzer, new() { diff --git a/DocGpt.Test/Verifiers/CSharpCodeFixVerifier`2.cs b/DocGpt.Test/Verifiers/CSharpCodeFixVerifier`2.cs index ecaeb92..7e0feba 100644 --- a/DocGpt.Test/Verifiers/CSharpCodeFixVerifier`2.cs +++ b/DocGpt.Test/Verifiers/CSharpCodeFixVerifier`2.cs @@ -1,8 +1,5 @@ namespace DocGpt.Test; -using System.Threading; -using System.Threading.Tasks; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Testing; @@ -10,6 +7,9 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Testing.Verifiers; +using System.Threading; +using System.Threading.Tasks; + public static partial class CSharpCodeFixVerifier where TAnalyzer : DiagnosticAnalyzer, new() where TCodeFix : CodeFixProvider, new() diff --git a/DocGpt.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs b/DocGpt.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs index f7d94a4..d995139 100644 --- a/DocGpt.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs +++ b/DocGpt.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs @@ -1,11 +1,11 @@ namespace DocGpt.Test; -using System.Threading; -using System.Threading.Tasks; - using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Testing; +using System.Threading; +using System.Threading.Tasks; + public static partial class CSharpCodeRefactoringVerifier where TCodeRefactoring : CodeRefactoringProvider, new() { diff --git a/DocGpt.Test/Verifiers/CSharpVerifierHelper.cs b/DocGpt.Test/Verifiers/CSharpVerifierHelper.cs index be54894..57b7526 100644 --- a/DocGpt.Test/Verifiers/CSharpVerifierHelper.cs +++ b/DocGpt.Test/Verifiers/CSharpVerifierHelper.cs @@ -1,11 +1,11 @@ namespace DocGpt.Test; -using System; -using System.Collections.Immutable; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Immutable; + internal static class CSharpVerifierHelper { /// diff --git a/DocGpt.Vsix/DocGpt.Vsix.csproj b/DocGpt.Vsix/DocGpt.Vsix.csproj index cec17cb..d60eadd 100644 --- a/DocGpt.Vsix/DocGpt.Vsix.csproj +++ b/DocGpt.Vsix/DocGpt.Vsix.csproj @@ -47,13 +47,13 @@ 4 - $(NuGetPackageRoot)Microsoft.VSSDK.Vsixsigntool\16.2.29116.78\tools\vssdk\vsixsigntool.exe - $(VsixSignTool) sign /f signing_cert.pfx /p "$(DOCGPT_SIGN_PASSWORD)" /fd sha256 - - - - - + $(NuGetPackageRoot)Microsoft.VSSDK.Vsixsigntool\16.2.29116.78\tools\vssdk\vsixsigntool.exe + $(VsixSignTool) sign /f signing_cert.pfx /p "$(DOCGPT_SIGN_PASSWORD)" /fd sha256 + + + + + Component @@ -92,12 +92,12 @@ - 1.0.0-beta.17 + 2.1.0 - 17.11.40262 + 17.12.40392 - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/DocGpt.Vsix/DocGptOptionsPage.cs b/DocGpt.Vsix/DocGptOptionsPage.cs index 6e531a4..6fb1389 100644 --- a/DocGpt.Vsix/DocGptOptionsPage.cs +++ b/DocGpt.Vsix/DocGptOptionsPage.cs @@ -1,13 +1,13 @@ namespace DocGpt.Vsix { - using System; - using System.ComponentModel; - using System.Runtime.InteropServices; - using DocGpt.Options; using Microsoft.VisualStudio.Shell; + using System; + using System.ComponentModel; + using System.Runtime.InteropServices; + /// /// The doc gpt options page. /// diff --git a/DocGpt.Vsix/DocGptPackage.cs b/DocGpt.Vsix/DocGptPackage.cs index 8768649..a5d9687 100644 --- a/DocGpt.Vsix/DocGptPackage.cs +++ b/DocGpt.Vsix/DocGptPackage.cs @@ -1,12 +1,12 @@ namespace DocGpt.Vsix { + using Microsoft.VisualStudio.Shell; + using Microsoft.VisualStudio.Shell.Interop; + using System; using System.Runtime.InteropServices; using System.Threading; - using Microsoft.VisualStudio.Shell; - using Microsoft.VisualStudio.Shell.Interop; - using Task = System.Threading.Tasks.Task; /// diff --git a/DocGpt.sln b/DocGpt.sln index 4e20d9e..d65bef4 100644 --- a/DocGpt.sln +++ b/DocGpt.sln @@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocGpt.Vsix", "DocGpt.Vsix\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solution Items", ".Solution Items", "{B21B7D0F-85AB-4643-8697-022056AAE095}" ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject @@ -31,7 +32,6 @@ Global {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Debug|x86.ActiveCfg = Debug|Any CPU {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Debug|x86.Build.0 = Debug|Any CPU {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Release|Any CPU.Build.0 = Release|Any CPU {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Release|arm64.ActiveCfg = Release|Any CPU {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Release|arm64.Build.0 = Release|Any CPU {AEF7FF2D-1E07-4A18-A951-91F19DD2ED9A}.Release|x86.ActiveCfg = Release|Any CPU