1195 lines
40 KiB
C#
Executable File
1195 lines
40 KiB
C#
Executable File
using MarketAlly.AIPlugin;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketAlly.AIPlugin.Refactoring.Plugins
|
|
{
|
|
[AIPlugin("EnhancedDocumentationGenerator", "Enhanced documentation generation with multiple styles and AI-powered descriptions")]
|
|
public class EnhancedDocumentationGeneratorPlugin : IAIPlugin
|
|
{
|
|
[AIParameter("Full path to the file to document", required: true)]
|
|
public string FilePath { get; set; }
|
|
|
|
[AIParameter("Documentation style: intelligent, comprehensive, basic, minimal", required: false)]
|
|
public string Style { get; set; } = "intelligent";
|
|
|
|
[AIParameter("Include examples in documentation", required: false)]
|
|
public bool IncludeExamples { get; set; } = false;
|
|
|
|
[AIParameter("Include see-also references", required: false)]
|
|
public bool IncludeSeeAlso { get; set; } = false;
|
|
|
|
[AIParameter("Generate API documentation format", required: false)]
|
|
public bool ApiDocFormat { get; set; } = false;
|
|
|
|
[AIParameter("Apply changes to file", required: false)]
|
|
public bool ApplyChanges { get; set; } = false;
|
|
|
|
[AIParameter("Scope of documentation: public, protected, internal, all", required: false)]
|
|
public string DocumentationScope { get; set; } = "public";
|
|
|
|
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
|
|
{
|
|
["filePath"] = typeof(string),
|
|
["filepath"] = typeof(string), // Allow lowercase
|
|
["style"] = typeof(string),
|
|
["includeExamples"] = typeof(bool),
|
|
["includeexamples"] = typeof(bool), // Allow lowercase
|
|
["includeSeeAlso"] = typeof(bool),
|
|
["includeseealso"] = typeof(bool), // Allow lowercase
|
|
["apiDocFormat"] = typeof(bool),
|
|
["apidocformat"] = typeof(bool), // Allow lowercase
|
|
["applyChanges"] = typeof(bool),
|
|
["applychanges"] = typeof(bool), // Allow lowercase
|
|
["documentationScope"] = typeof(string),
|
|
["documentationscope"] = typeof(string) // Allow lowercase
|
|
};
|
|
|
|
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
|
|
{
|
|
try
|
|
{
|
|
// Extract parameters with case-insensitive handling
|
|
string filePath = GetParameterValue(parameters, "filePath", "filepath")?.ToString();
|
|
string style = GetParameterValue(parameters, "style")?.ToString()?.ToLower() ?? "intelligent";
|
|
bool includeExamples = GetBoolParameter(parameters, "includeExamples", "includeexamples");
|
|
bool includeSeeAlso = GetBoolParameter(parameters, "includeSeeAlso", "includeseealso");
|
|
bool apiDocFormat = GetBoolParameter(parameters, "apiDocFormat", "apidocformat");
|
|
bool applyChanges = GetBoolParameter(parameters, "applyChanges", "applychanges");
|
|
string scope = GetParameterValue(parameters, "documentationScope", "documentationscope")?.ToString()?.ToLower() ?? "public";
|
|
|
|
// Validate file exists
|
|
if (!File.Exists(filePath))
|
|
{
|
|
return new AIPluginResult(
|
|
new FileNotFoundException($"File not found: {filePath}"),
|
|
"File not found"
|
|
);
|
|
}
|
|
|
|
// Read and parse the file
|
|
var sourceCode = await File.ReadAllTextAsync(filePath);
|
|
var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
|
|
var root = syntaxTree.GetRoot();
|
|
|
|
// Analyze the code structure
|
|
var codeAnalysis = await AnalyzeCodeStructure(root, filePath, scope);
|
|
|
|
if (codeAnalysis.MembersNeedingDocumentation.Count == 0)
|
|
{
|
|
return new AIPluginResult(new
|
|
{
|
|
Message = "No members found that need documentation",
|
|
FilePath = filePath,
|
|
MembersAnalyzed = codeAnalysis.TotalMembers,
|
|
Scope = scope,
|
|
ChangesMade = false
|
|
});
|
|
}
|
|
|
|
// Generate documentation based on style
|
|
var documentationSuggestions = await GenerateDocumentationByStyle(
|
|
codeAnalysis,
|
|
sourceCode,
|
|
style,
|
|
includeExamples,
|
|
includeSeeAlso,
|
|
apiDocFormat
|
|
);
|
|
|
|
// Apply documentation to the code
|
|
var modifiedContent = ApplyDocumentationToCode(sourceCode, documentationSuggestions);
|
|
|
|
// Calculate statistics
|
|
var stats = CalculateDocumentationStats(documentationSuggestions, codeAnalysis);
|
|
|
|
if (applyChanges)
|
|
{
|
|
// Create backup
|
|
var backupPath = $"{filePath}.{DateTime.Now:yyyyMMdd_HHmmss}.bak";
|
|
File.Copy(filePath, backupPath);
|
|
|
|
// Write modified content
|
|
await File.WriteAllTextAsync(filePath, modifiedContent, Encoding.UTF8);
|
|
|
|
return new AIPluginResult(new
|
|
{
|
|
Message = $"Successfully added {style} documentation to {documentationSuggestions.Count} members",
|
|
FilePath = filePath,
|
|
BackupPath = backupPath,
|
|
Style = style,
|
|
ChangesMade = true,
|
|
Statistics = stats,
|
|
ModifiedContent = modifiedContent,
|
|
Timestamp = DateTime.UtcNow
|
|
});
|
|
}
|
|
else
|
|
{
|
|
return new AIPluginResult(new
|
|
{
|
|
Message = $"Preview: Would add {style} documentation to {documentationSuggestions.Count} members",
|
|
FilePath = filePath,
|
|
Style = style,
|
|
ChangesMade = false,
|
|
Statistics = stats,
|
|
PreviewContent = modifiedContent,
|
|
DocumentationSuggestions = documentationSuggestions.Select(s => new
|
|
{
|
|
Member = s.Member.Name,
|
|
Type = s.Member.Type,
|
|
LineNumber = s.Member.LineNumber,
|
|
Documentation = s.DocumentationLines,
|
|
Quality = s.QualityScore
|
|
}).ToList(),
|
|
Timestamp = DateTime.UtcNow
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new AIPluginResult(ex, $"Enhanced documentation generation failed: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private object GetParameterValue(IReadOnlyDictionary<string, object> parameters, params string[] keys)
|
|
{
|
|
foreach (var key in keys)
|
|
{
|
|
if (parameters.TryGetValue(key, out var value))
|
|
return value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private bool GetBoolParameter(IReadOnlyDictionary<string, object> parameters, params string[] keys)
|
|
{
|
|
var value = GetParameterValue(parameters, keys);
|
|
return value != null && Convert.ToBoolean(value);
|
|
}
|
|
|
|
private async Task<EnhancedCodeAnalysis> AnalyzeCodeStructure(SyntaxNode root, string filePath, string scope)
|
|
{
|
|
var analysis = new EnhancedCodeAnalysis
|
|
{
|
|
FilePath = filePath,
|
|
MembersNeedingDocumentation = new List<EnhancedCodeMember>()
|
|
};
|
|
|
|
var accessibilityFilter = GetAccessibilityFilter(scope);
|
|
|
|
// Analyze classes
|
|
var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
|
|
foreach (var cls in classes)
|
|
{
|
|
if (ShouldDocumentMember(cls, accessibilityFilter) && !HasDocumentation(cls))
|
|
{
|
|
var member = await CreateEnhancedCodeMember(cls, "class", root);
|
|
analysis.MembersNeedingDocumentation.Add(member);
|
|
}
|
|
analysis.TotalMembers++;
|
|
}
|
|
|
|
// Analyze interfaces
|
|
var interfaces = root.DescendantNodes().OfType<InterfaceDeclarationSyntax>();
|
|
foreach (var iface in interfaces)
|
|
{
|
|
if (ShouldDocumentMember(iface, accessibilityFilter) && !HasDocumentation(iface))
|
|
{
|
|
var member = await CreateEnhancedCodeMember(iface, "interface", root);
|
|
analysis.MembersNeedingDocumentation.Add(member);
|
|
}
|
|
analysis.TotalMembers++;
|
|
}
|
|
|
|
// Analyze methods
|
|
var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
|
|
foreach (var method in methods)
|
|
{
|
|
if (ShouldDocumentMember(method, accessibilityFilter) && !HasDocumentation(method))
|
|
{
|
|
var member = await CreateEnhancedCodeMember(method, "method", root);
|
|
analysis.MembersNeedingDocumentation.Add(member);
|
|
}
|
|
analysis.TotalMembers++;
|
|
}
|
|
|
|
// Analyze properties
|
|
var properties = root.DescendantNodes().OfType<PropertyDeclarationSyntax>();
|
|
foreach (var prop in properties)
|
|
{
|
|
if (ShouldDocumentMember(prop, accessibilityFilter) && !HasDocumentation(prop))
|
|
{
|
|
var member = await CreateEnhancedCodeMember(prop, "property", root);
|
|
analysis.MembersNeedingDocumentation.Add(member);
|
|
}
|
|
analysis.TotalMembers++;
|
|
}
|
|
|
|
// Analyze events
|
|
var events = root.DescendantNodes().OfType<EventDeclarationSyntax>();
|
|
foreach (var evt in events)
|
|
{
|
|
if (ShouldDocumentMember(evt, accessibilityFilter) && !HasDocumentation(evt))
|
|
{
|
|
var member = await CreateEnhancedCodeMember(evt, "event", root);
|
|
analysis.MembersNeedingDocumentation.Add(member);
|
|
}
|
|
analysis.TotalMembers++;
|
|
}
|
|
|
|
return analysis;
|
|
}
|
|
|
|
private async Task<EnhancedCodeMember> CreateEnhancedCodeMember(SyntaxNode node, string type, SyntaxNode root)
|
|
{
|
|
var og = node.GetText().Lines.FirstOrDefault();
|
|
var member = new EnhancedCodeMember
|
|
{
|
|
Type = type,
|
|
LineNumber = node.GetLocation().GetLineSpan().StartLinePosition.Line + 1,
|
|
OriginalLine = (og == null) ? "" : og.ToString(),
|
|
IndentLevel = GetIndentLevel(node),
|
|
Context = await AnalyzeMemberContext(node, root)
|
|
};
|
|
|
|
// Extract member-specific information
|
|
switch (node)
|
|
{
|
|
case ClassDeclarationSyntax cls:
|
|
member.Name = cls.Identifier.ValueText;
|
|
member.Accessibility = GetAccessibility(cls.Modifiers);
|
|
member.IsStatic = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
|
|
member.IsAbstract = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword));
|
|
member.BaseTypes = cls.BaseList?.Types.Select(t => t.ToString()).ToList() ?? new List<string>();
|
|
break;
|
|
|
|
case InterfaceDeclarationSyntax iface:
|
|
member.Name = iface.Identifier.ValueText;
|
|
member.Accessibility = GetAccessibility(iface.Modifiers);
|
|
member.BaseTypes = iface.BaseList?.Types.Select(t => t.ToString()).ToList() ?? new List<string>();
|
|
break;
|
|
|
|
case MethodDeclarationSyntax method:
|
|
member.Name = method.Identifier.ValueText;
|
|
member.Accessibility = GetAccessibility(method.Modifiers);
|
|
member.IsStatic = method.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
|
|
member.IsAsync = method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword));
|
|
member.Parameters = ExtractParameters(method.ParameterList);
|
|
member.ReturnType = method.ReturnType.ToString();
|
|
member.IsOverride = method.Modifiers.Any(m => m.IsKind(SyntaxKind.OverrideKeyword));
|
|
member.IsVirtual = method.Modifiers.Any(m => m.IsKind(SyntaxKind.VirtualKeyword));
|
|
break;
|
|
|
|
case PropertyDeclarationSyntax prop:
|
|
member.Name = prop.Identifier.ValueText;
|
|
member.Accessibility = GetAccessibility(prop.Modifiers);
|
|
member.IsStatic = prop.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
|
|
member.ReturnType = prop.Type.ToString();
|
|
member.HasGetter = prop.AccessorList?.Accessors.Any(a => a.IsKind(SyntaxKind.GetAccessorDeclaration)) ?? false;
|
|
member.HasSetter = prop.AccessorList?.Accessors.Any(a => a.IsKind(SyntaxKind.SetAccessorDeclaration)) ?? false;
|
|
break;
|
|
|
|
case EventDeclarationSyntax evt:
|
|
member.Name = evt.Identifier.ValueText;
|
|
member.Accessibility = GetAccessibility(evt.Modifiers);
|
|
member.IsStatic = evt.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
|
|
member.ReturnType = evt.Type.ToString();
|
|
break;
|
|
}
|
|
|
|
return member;
|
|
}
|
|
|
|
private async Task<MemberContext> AnalyzeMemberContext(SyntaxNode node, SyntaxNode root)
|
|
{
|
|
var context = new MemberContext();
|
|
|
|
// Find containing class/interface
|
|
var containingType = node.Ancestors().OfType<TypeDeclarationSyntax>().FirstOrDefault();
|
|
if (containingType != null)
|
|
{
|
|
context.ContainingTypeName = containingType switch
|
|
{
|
|
ClassDeclarationSyntax cls => cls.Identifier.ValueText,
|
|
InterfaceDeclarationSyntax iface => iface.Identifier.ValueText,
|
|
_ => containingType.ToString()
|
|
};
|
|
}
|
|
|
|
// Find namespace
|
|
var namespaceDeclaration = node.Ancestors().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();
|
|
if (namespaceDeclaration != null)
|
|
{
|
|
context.Namespace = namespaceDeclaration.Name.ToString();
|
|
}
|
|
|
|
// Analyze usage patterns
|
|
if (node is MethodDeclarationSyntax method)
|
|
{
|
|
context.UsagePatterns = AnalyzeMethodUsage(method);
|
|
context.ComplexityScore = CalculateMethodComplexity(method);
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
private async Task<List<EnhancedDocumentationSuggestion>> GenerateDocumentationByStyle(
|
|
EnhancedCodeAnalysis analysis,
|
|
string sourceCode,
|
|
string style,
|
|
bool includeExamples,
|
|
bool includeSeeAlso,
|
|
bool apiDocFormat)
|
|
{
|
|
var suggestions = new List<EnhancedDocumentationSuggestion>();
|
|
|
|
foreach (var member in analysis.MembersNeedingDocumentation)
|
|
{
|
|
var suggestion = new EnhancedDocumentationSuggestion
|
|
{
|
|
Member = member,
|
|
DocumentationLines = new List<string>()
|
|
};
|
|
|
|
var indent = new string('\t', member.IndentLevel);
|
|
|
|
switch (style)
|
|
{
|
|
case "intelligent":
|
|
await GenerateIntelligentDocumentation(suggestion, member, indent, includeExamples, includeSeeAlso);
|
|
break;
|
|
case "comprehensive":
|
|
await GenerateComprehensiveDocumentation(suggestion, member, indent, includeExamples, includeSeeAlso, apiDocFormat);
|
|
break;
|
|
case "basic":
|
|
await GenerateBasicDocumentation(suggestion, member, indent);
|
|
break;
|
|
case "minimal":
|
|
await GenerateMinimalDocumentation(suggestion, member, indent);
|
|
break;
|
|
default:
|
|
await GenerateIntelligentDocumentation(suggestion, member, indent, includeExamples, includeSeeAlso);
|
|
break;
|
|
}
|
|
|
|
// Calculate quality score
|
|
suggestion.QualityScore = CalculateDocumentationQuality(suggestion, member);
|
|
suggestions.Add(suggestion);
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
private async Task GenerateIntelligentDocumentation(
|
|
EnhancedDocumentationSuggestion suggestion,
|
|
EnhancedCodeMember member,
|
|
string indent,
|
|
bool includeExamples,
|
|
bool includeSeeAlso)
|
|
{
|
|
var docs = suggestion.DocumentationLines;
|
|
|
|
docs.Add($"{indent}/// <summary>");
|
|
|
|
// Generate intelligent description based on member analysis
|
|
var description = GenerateIntelligentDescription(member);
|
|
docs.Add($"{indent}/// {description}");
|
|
docs.Add($"{indent}/// </summary>");
|
|
|
|
// Add type parameters for generic types
|
|
if (member.Type == "class" || member.Type == "interface" || member.Type == "method")
|
|
{
|
|
// This would need more sophisticated generic type analysis
|
|
// For now, we'll keep it simple
|
|
}
|
|
|
|
// Add parameters documentation
|
|
if (member.Parameters?.Count > 0)
|
|
{
|
|
foreach (var param in member.Parameters)
|
|
{
|
|
var paramDescription = GenerateIntelligentParameterDescription(param, member);
|
|
docs.Add($"{indent}/// <param name=\"{param.Name}\">{paramDescription}</param>");
|
|
}
|
|
}
|
|
|
|
// Add return documentation
|
|
if (!string.IsNullOrEmpty(member.ReturnType) && member.ReturnType != "void")
|
|
{
|
|
var returnDescription = GenerateIntelligentReturnDescription(member);
|
|
docs.Add($"{indent}/// <returns>{returnDescription}</returns>");
|
|
}
|
|
|
|
// Add exceptions for methods with complexity
|
|
if (member.Type == "method" && member.Context?.ComplexityScore > 5)
|
|
{
|
|
var exceptions = GenerateExceptionDocumentation(member);
|
|
foreach (var exception in exceptions)
|
|
{
|
|
docs.Add($"{indent}/// <exception cref=\"{exception.Type}\">{exception.Description}</exception>");
|
|
}
|
|
}
|
|
|
|
// Add examples if requested
|
|
if (includeExamples && ShouldIncludeExample(member))
|
|
{
|
|
await GenerateExampleDocumentation(docs, member, indent);
|
|
}
|
|
|
|
// Add see-also references if requested
|
|
if (includeSeeAlso)
|
|
{
|
|
var seeAlsoRefs = GenerateSeeAlsoReferences(member);
|
|
foreach (var seeAlso in seeAlsoRefs)
|
|
{
|
|
docs.Add($"{indent}/// <seealso cref=\"{seeAlso}\"/>");
|
|
}
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task GenerateComprehensiveDocumentation(
|
|
EnhancedDocumentationSuggestion suggestion,
|
|
EnhancedCodeMember member,
|
|
string indent,
|
|
bool includeExamples,
|
|
bool includeSeeAlso,
|
|
bool apiDocFormat)
|
|
{
|
|
// Start with intelligent documentation
|
|
await GenerateIntelligentDocumentation(suggestion, member, indent, true, includeSeeAlso);
|
|
|
|
var docs = suggestion.DocumentationLines;
|
|
|
|
// Add additional comprehensive elements
|
|
if (member.Type == "method")
|
|
{
|
|
// Add complexity information as remarks
|
|
if (member.Context?.ComplexityScore > 3)
|
|
{
|
|
docs.Add($"{indent}/// <remarks>");
|
|
docs.Add($"{indent}/// This method has a complexity score of {member.Context.ComplexityScore}. ");
|
|
docs.Add($"{indent}/// Consider refactoring if the complexity grows further.");
|
|
docs.Add($"{indent}/// </remarks>");
|
|
}
|
|
|
|
// Add performance considerations
|
|
if (member.Context?.UsagePatterns?.Contains("loop") == true)
|
|
{
|
|
docs.Add($"{indent}/// <remarks>");
|
|
docs.Add($"{indent}/// Performance consideration: This method contains loops. ");
|
|
docs.Add($"{indent}/// Consider the input size when calling this method.");
|
|
docs.Add($"{indent}/// </remarks>");
|
|
}
|
|
}
|
|
|
|
// Add version information for API documentation
|
|
if (apiDocFormat)
|
|
{
|
|
docs.Add($"{indent}/// <since>1.0.0</since>");
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task GenerateBasicDocumentation(
|
|
EnhancedDocumentationSuggestion suggestion,
|
|
EnhancedCodeMember member,
|
|
string indent)
|
|
{
|
|
var docs = suggestion.DocumentationLines;
|
|
|
|
docs.Add($"{indent}/// <summary>");
|
|
docs.Add($"{indent}/// {GenerateBasicDescription(member)}");
|
|
docs.Add($"{indent}/// </summary>");
|
|
|
|
// Basic parameter documentation
|
|
if (member.Parameters?.Count > 0)
|
|
{
|
|
foreach (var param in member.Parameters)
|
|
{
|
|
docs.Add($"{indent}/// <param name=\"{param.Name}\">The {param.Name} parameter</param>");
|
|
}
|
|
}
|
|
|
|
// Basic return documentation
|
|
if (!string.IsNullOrEmpty(member.ReturnType) && member.ReturnType != "void")
|
|
{
|
|
docs.Add($"{indent}/// <returns>The {member.ReturnType.ToLower()} result</returns>");
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task GenerateMinimalDocumentation(
|
|
EnhancedDocumentationSuggestion suggestion,
|
|
EnhancedCodeMember member,
|
|
string indent)
|
|
{
|
|
var docs = suggestion.DocumentationLines;
|
|
|
|
docs.Add($"{indent}/// <summary>");
|
|
docs.Add($"{indent}/// {member.Name}");
|
|
docs.Add($"{indent}/// </summary>");
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private string GenerateIntelligentDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
var type = member.Type;
|
|
|
|
switch (type)
|
|
{
|
|
case "class":
|
|
return GenerateClassDescription(member);
|
|
case "interface":
|
|
return GenerateInterfaceDescription(member);
|
|
case "method":
|
|
return GenerateMethodDescription(member);
|
|
case "property":
|
|
return GeneratePropertyDescription(member);
|
|
case "event":
|
|
return GenerateEventDescription(member);
|
|
default:
|
|
return $"Represents {SplitCamelCase(name).ToLower()}";
|
|
}
|
|
}
|
|
|
|
private string GenerateClassDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
var description = new StringBuilder();
|
|
|
|
// Analyze naming patterns
|
|
if (name.EndsWith("Service"))
|
|
description.Append($"Provides services for {SplitCamelCase(name.Replace("Service", "")).ToLower()}");
|
|
else if (name.EndsWith("Controller"))
|
|
description.Append($"Handles requests for {SplitCamelCase(name.Replace("Controller", "")).ToLower()}");
|
|
else if (name.EndsWith("Repository"))
|
|
description.Append($"Manages data operations for {SplitCamelCase(name.Replace("Repository", "")).ToLower()}");
|
|
else if (name.EndsWith("Manager"))
|
|
description.Append($"Manages {SplitCamelCase(name.Replace("Manager", "")).ToLower()} operations");
|
|
else if (name.EndsWith("Factory"))
|
|
description.Append($"Creates instances of {SplitCamelCase(name.Replace("Factory", "")).ToLower()}");
|
|
else if (name.EndsWith("Builder"))
|
|
description.Append($"Builds {SplitCamelCase(name.Replace("Builder", "")).ToLower()} objects");
|
|
else if (name.EndsWith("Helper"))
|
|
description.Append($"Provides helper methods for {SplitCamelCase(name.Replace("Helper", "")).ToLower()}");
|
|
else if (name.EndsWith("Utility") || name.EndsWith("Utils"))
|
|
description.Append($"Utility class for {SplitCamelCase(name.Replace("Utility", "").Replace("Utils", "")).ToLower()}");
|
|
else if (name.EndsWith("Exception"))
|
|
description.Append($"Exception thrown when {SplitCamelCase(name.Replace("Exception", "")).ToLower()} occurs");
|
|
else if (name.EndsWith("Attribute"))
|
|
description.Append($"Attribute for {SplitCamelCase(name.Replace("Attribute", "")).ToLower()}");
|
|
else if (name.EndsWith("Plugin"))
|
|
description.Append($"Plugin that provides {SplitCamelCase(name.Replace("Plugin", "")).ToLower()} functionality");
|
|
else
|
|
description.Append($"Represents a {SplitCamelCase(name).ToLower()}");
|
|
|
|
// Add inheritance information
|
|
if (member.BaseTypes?.Any() == true)
|
|
{
|
|
var baseType = member.BaseTypes.First();
|
|
if (!baseType.Equals("object", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
description.Append($" that extends {baseType}");
|
|
}
|
|
}
|
|
|
|
// Add modifiers context
|
|
if (member.IsAbstract)
|
|
description.Append(". This is an abstract class");
|
|
else if (member.IsStatic)
|
|
description.Append(". This is a static class");
|
|
|
|
return description.ToString();
|
|
}
|
|
|
|
private string GenerateInterfaceDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
var cleanName = name.StartsWith("I") && char.IsUpper(name, 1)
|
|
? name.Substring(1)
|
|
: name;
|
|
|
|
return $"Defines the contract for {SplitCamelCase(cleanName).ToLower()} operations";
|
|
}
|
|
|
|
private string GenerateMethodDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
var asyncPrefix = member.IsAsync ? "Asynchronously " : "";
|
|
|
|
// Common method patterns
|
|
if (name.StartsWith("Get"))
|
|
return $"{asyncPrefix}gets {SplitCamelCase(name.Substring(3)).ToLower()}";
|
|
else if (name.StartsWith("Set"))
|
|
return $"{asyncPrefix}sets {SplitCamelCase(name.Substring(3)).ToLower()}";
|
|
else if (name.StartsWith("Create"))
|
|
return $"{asyncPrefix}creates {SplitCamelCase(name.Substring(6)).ToLower()}";
|
|
else if (name.StartsWith("Update"))
|
|
return $"{asyncPrefix}updates {SplitCamelCase(name.Substring(6)).ToLower()}";
|
|
else if (name.StartsWith("Delete") || name.StartsWith("Remove"))
|
|
return $"{asyncPrefix}deletes {SplitCamelCase(name.Substring(6)).ToLower()}";
|
|
else if (name.StartsWith("Calculate"))
|
|
return $"{asyncPrefix}calculates {SplitCamelCase(name.Substring(9)).ToLower()}";
|
|
else if (name.StartsWith("Process"))
|
|
return $"{asyncPrefix}processes {SplitCamelCase(name.Substring(7)).ToLower()}";
|
|
else if (name.StartsWith("Execute"))
|
|
return $"{asyncPrefix}executes {SplitCamelCase(name.Substring(7)).ToLower()}";
|
|
else if (name.StartsWith("Handle"))
|
|
return $"{asyncPrefix}handles {SplitCamelCase(name.Substring(6)).ToLower()}";
|
|
else if (name.StartsWith("Parse"))
|
|
return $"{asyncPrefix}parses {SplitCamelCase(name.Substring(5)).ToLower()}";
|
|
else if (name.StartsWith("Convert"))
|
|
return $"{asyncPrefix}converts {SplitCamelCase(name.Substring(7)).ToLower()}";
|
|
else if (name.StartsWith("Validate"))
|
|
return $"{asyncPrefix}validates {SplitCamelCase(name.Substring(8)).ToLower()}";
|
|
else if (name.StartsWith("Initialize") || name.StartsWith("Init"))
|
|
return $"{asyncPrefix}initializes {SplitCamelCase(name.Replace("Initialize", "").Replace("Init", "")).ToLower()}";
|
|
else if (name.StartsWith("Build"))
|
|
return $"{asyncPrefix}builds {SplitCamelCase(name.Substring(5)).ToLower()}";
|
|
else if (name.StartsWith("Configure"))
|
|
return $"{asyncPrefix}configures {SplitCamelCase(name.Substring(9)).ToLower()}";
|
|
else if (name.StartsWith("Load"))
|
|
return $"{asyncPrefix}loads {SplitCamelCase(name.Substring(4)).ToLower()}";
|
|
else if (name.StartsWith("Save"))
|
|
return $"{asyncPrefix}saves {SplitCamelCase(name.Substring(4)).ToLower()}";
|
|
else if (name.StartsWith("Find"))
|
|
return $"{asyncPrefix}finds {SplitCamelCase(name.Substring(4)).ToLower()}";
|
|
else if (name.StartsWith("Search"))
|
|
return $"{asyncPrefix}searches for {SplitCamelCase(name.Substring(6)).ToLower()}";
|
|
else if (name.StartsWith("Check") || name.StartsWith("Is") || name.StartsWith("Has") || name.StartsWith("Can"))
|
|
return $"{asyncPrefix}checks if {SplitCamelCase(name).ToLower()}";
|
|
else
|
|
return $"{asyncPrefix}executes the {SplitCamelCase(name).ToLower()} operation";
|
|
}
|
|
|
|
private string GeneratePropertyDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
var accessDescription = "";
|
|
|
|
if (member.HasGetter && member.HasSetter)
|
|
accessDescription = "Gets or sets";
|
|
else if (member.HasGetter)
|
|
accessDescription = "Gets";
|
|
else if (member.HasSetter)
|
|
accessDescription = "Sets";
|
|
|
|
return $"{accessDescription} the {SplitCamelCase(name).ToLower()}";
|
|
}
|
|
|
|
private string GenerateEventDescription(EnhancedCodeMember member)
|
|
{
|
|
var name = member.Name;
|
|
return $"Occurs when {SplitCamelCase(name).ToLower()}";
|
|
}
|
|
|
|
private string GenerateBasicDescription(EnhancedCodeMember member)
|
|
{
|
|
return $"{member.Type.Substring(0, 1).ToUpper() + member.Type.Substring(1)} for {member.Name}";
|
|
}
|
|
|
|
private string GenerateIntelligentParameterDescription(ParameterInfo param, EnhancedCodeMember member)
|
|
{
|
|
var name = param.Name.ToLower();
|
|
var type = param.Type.ToLower();
|
|
|
|
// Common parameter patterns
|
|
if (name.Contains("path") || name.Contains("filepath") || name.Contains("filename"))
|
|
return "The file or directory path";
|
|
else if (name.Contains("id") || name.Contains("identifier"))
|
|
return "The unique identifier";
|
|
else if (name.Contains("name"))
|
|
return "The name value";
|
|
else if (name.Contains("count") || name.Contains("number"))
|
|
return "The number of items";
|
|
else if (name.Contains("index"))
|
|
return "The zero-based index";
|
|
else if (name.Contains("content") || name.Contains("data"))
|
|
return "The content data";
|
|
else if (name.Contains("message") || name.Contains("text"))
|
|
return "The message or text";
|
|
else if (name.Contains("url") || name.Contains("uri"))
|
|
return "The URL address";
|
|
else if (name.Contains("token"))
|
|
return "The authentication token";
|
|
else if (name.Contains("config") || name.Contains("settings"))
|
|
return "The configuration settings";
|
|
else if (name.Contains("callback") || name.Contains("action"))
|
|
return "The callback action to execute";
|
|
else if (name.Contains("predicate") || name.Contains("filter"))
|
|
return "The filtering condition";
|
|
else if (type.Contains("bool"))
|
|
return $"True to {SplitCamelCase(param.Name).ToLower()}, otherwise false";
|
|
else if (type.Contains("cancellation"))
|
|
return "The cancellation token";
|
|
else
|
|
return $"The {SplitCamelCase(param.Name).ToLower()} parameter";
|
|
}
|
|
|
|
private string GenerateIntelligentReturnDescription(EnhancedCodeMember member)
|
|
{
|
|
var returnType = member.ReturnType.ToLower();
|
|
var methodName = member.Name.ToLower();
|
|
|
|
if (returnType == "task")
|
|
return "A task representing the asynchronous operation";
|
|
else if (returnType.Contains("task<"))
|
|
{
|
|
var innerType = ExtractGenericType(member.ReturnType);
|
|
return $"A task containing the {innerType.ToLower()} result";
|
|
}
|
|
else if (returnType == "bool" || returnType == "boolean")
|
|
{
|
|
if (methodName.StartsWith("is") || methodName.StartsWith("has") || methodName.StartsWith("can") || methodName.StartsWith("check"))
|
|
return "True if the condition is met, otherwise false";
|
|
else
|
|
return "True if successful, otherwise false";
|
|
}
|
|
else if (returnType == "string")
|
|
return "The resulting string value";
|
|
else if (returnType == "int" || returnType == "integer")
|
|
return "The resulting integer value";
|
|
else if (returnType.Contains("list") || returnType.Contains("collection") || returnType.Contains("enumerable"))
|
|
return "A collection of results";
|
|
else if (methodName.StartsWith("get"))
|
|
return $"The requested {SplitCamelCase(methodName.Substring(3)).ToLower()}";
|
|
else if (methodName.StartsWith("create"))
|
|
return $"The created {SplitCamelCase(methodName.Substring(6)).ToLower()}";
|
|
else if (methodName.StartsWith("calculate"))
|
|
return $"The calculated {SplitCamelCase(methodName.Substring(9)).ToLower()}";
|
|
else
|
|
return $"The {member.ReturnType.ToLower()} result";
|
|
}
|
|
|
|
// Helper methods continue...
|
|
private async Task GenerateExampleDocumentation(List<string> docs, EnhancedCodeMember member, string indent)
|
|
{
|
|
if (!ShouldIncludeExample(member)) return;
|
|
|
|
docs.Add($"{indent}/// <example>");
|
|
docs.Add($"{indent}/// <code>");
|
|
|
|
switch (member.Type)
|
|
{
|
|
case "method":
|
|
if (member.IsStatic)
|
|
{
|
|
docs.Add($"{indent}/// // Example usage:");
|
|
if (member.Parameters?.Any() == true)
|
|
{
|
|
var exampleParams = GenerateExampleParameters(member.Parameters);
|
|
docs.Add($"{indent}/// var result = {member.Context?.ContainingTypeName}.{member.Name}({exampleParams});");
|
|
}
|
|
else
|
|
{
|
|
docs.Add($"{indent}/// var result = {member.Context?.ContainingTypeName}.{member.Name}();");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
docs.Add($"{indent}/// // Example usage:");
|
|
docs.Add($"{indent}/// var instance = new {member.Context?.ContainingTypeName}();");
|
|
if (member.Parameters?.Any() == true)
|
|
{
|
|
var exampleParams = GenerateExampleParameters(member.Parameters);
|
|
docs.Add($"{indent}/// var result = instance.{member.Name}({exampleParams});");
|
|
}
|
|
else
|
|
{
|
|
docs.Add($"{indent}/// var result = instance.{member.Name}();");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "property":
|
|
docs.Add($"{indent}/// // Example usage:");
|
|
docs.Add($"{indent}/// var instance = new {member.Context?.ContainingTypeName}();");
|
|
if (member.HasSetter)
|
|
{
|
|
docs.Add($"{indent}/// instance.{member.Name} = {GenerateExampleValue(member.ReturnType)};");
|
|
}
|
|
if (member.HasGetter)
|
|
{
|
|
docs.Add($"{indent}/// var value = instance.{member.Name};");
|
|
}
|
|
break;
|
|
|
|
case "class":
|
|
docs.Add($"{indent}/// // Example usage:");
|
|
docs.Add($"{indent}/// var instance = new {member.Name}();");
|
|
break;
|
|
}
|
|
|
|
docs.Add($"{indent}/// </code>");
|
|
docs.Add($"{indent}/// </example>");
|
|
}
|
|
|
|
private string GenerateExampleParameters(List<ParameterInfo> parameters)
|
|
{
|
|
return string.Join(", ", parameters.Select(p => GenerateExampleValue(p.Type)));
|
|
}
|
|
|
|
private string GenerateExampleValue(string type)
|
|
{
|
|
var lowerType = type.ToLower();
|
|
|
|
if (lowerType.Contains("string"))
|
|
return "\"example\"";
|
|
else if (lowerType.Contains("int") || lowerType.Contains("integer"))
|
|
return "42";
|
|
else if (lowerType.Contains("bool"))
|
|
return "true";
|
|
else if (lowerType.Contains("double") || lowerType.Contains("decimal"))
|
|
return "3.14";
|
|
else if (lowerType.Contains("datetime"))
|
|
return "DateTime.Now";
|
|
else if (lowerType.Contains("guid"))
|
|
return "Guid.NewGuid()";
|
|
else
|
|
return "null";
|
|
}
|
|
|
|
private List<ExceptionDocumentation> GenerateExceptionDocumentation(EnhancedCodeMember member)
|
|
{
|
|
var exceptions = new List<ExceptionDocumentation>();
|
|
|
|
// Common exceptions based on method patterns
|
|
if (member.Parameters?.Any(p => p.Type.Contains("string")) == true)
|
|
{
|
|
exceptions.Add(new ExceptionDocumentation
|
|
{
|
|
Type = "ArgumentNullException",
|
|
Description = "Thrown when a required parameter is null"
|
|
});
|
|
}
|
|
|
|
if (member.Name.ToLower().Contains("file") || member.Parameters?.Any(p => p.Name.ToLower().Contains("path")) == true)
|
|
{
|
|
exceptions.Add(new ExceptionDocumentation
|
|
{
|
|
Type = "FileNotFoundException",
|
|
Description = "Thrown when the specified file cannot be found"
|
|
});
|
|
}
|
|
|
|
if (member.Name.ToLower().Contains("parse") || member.Name.ToLower().Contains("convert"))
|
|
{
|
|
exceptions.Add(new ExceptionDocumentation
|
|
{
|
|
Type = "FormatException",
|
|
Description = "Thrown when the input format is invalid"
|
|
});
|
|
}
|
|
|
|
return exceptions;
|
|
}
|
|
|
|
private List<string> GenerateSeeAlsoReferences(EnhancedCodeMember member)
|
|
{
|
|
var references = new List<string>();
|
|
|
|
// Add related types from base classes
|
|
if (member.BaseTypes?.Any() == true)
|
|
{
|
|
references.AddRange(member.BaseTypes);
|
|
}
|
|
|
|
// Add related types from parameters
|
|
if (member.Parameters?.Any() == true)
|
|
{
|
|
var complexTypes = member.Parameters
|
|
.Where(p => !IsBuiltInType(p.Type))
|
|
.Select(p => p.Type)
|
|
.Distinct();
|
|
references.AddRange(complexTypes);
|
|
}
|
|
|
|
// Add return type if it's a complex type
|
|
if (!string.IsNullOrEmpty(member.ReturnType) && !IsBuiltInType(member.ReturnType))
|
|
{
|
|
references.Add(member.ReturnType);
|
|
}
|
|
|
|
return references.Take(3).ToList(); // Limit to top 3 references
|
|
}
|
|
|
|
private bool ShouldIncludeExample(EnhancedCodeMember member)
|
|
{
|
|
// Include examples for public methods with parameters or complex return types
|
|
return member.Accessibility == "public" &&
|
|
(member.Parameters?.Any() == true ||
|
|
(!string.IsNullOrEmpty(member.ReturnType) && !IsBuiltInType(member.ReturnType)));
|
|
}
|
|
|
|
private bool IsBuiltInType(string type)
|
|
{
|
|
var builtInTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
"string", "int", "bool", "double", "float", "decimal", "char", "byte",
|
|
"short", "long", "object", "void", "DateTime", "Guid", "TimeSpan"
|
|
};
|
|
|
|
return builtInTypes.Contains(type.Split('<')[0].Trim());
|
|
}
|
|
|
|
private string ExtractGenericType(string type)
|
|
{
|
|
var match = Regex.Match(type, @"<(.+?)>");
|
|
return match.Success ? match.Groups[1].Value : type;
|
|
}
|
|
|
|
private double CalculateDocumentationQuality(EnhancedDocumentationSuggestion suggestion, EnhancedCodeMember member)
|
|
{
|
|
double score = 0;
|
|
|
|
// Base score for having documentation
|
|
score += 20;
|
|
|
|
// Score for summary
|
|
var summaryLines = suggestion.DocumentationLines.Count(l => l.Contains("<summary>") || l.Contains("</summary>"));
|
|
if (summaryLines >= 2) score += 25;
|
|
|
|
// Score for parameter documentation
|
|
if (member.Parameters?.Any() == true)
|
|
{
|
|
var paramDocCount = suggestion.DocumentationLines.Count(l => l.Contains("<param"));
|
|
var paramCoverage = (double)paramDocCount / member.Parameters.Count;
|
|
score += paramCoverage * 20;
|
|
}
|
|
|
|
// Score for return documentation
|
|
if (!string.IsNullOrEmpty(member.ReturnType) && member.ReturnType != "void")
|
|
{
|
|
if (suggestion.DocumentationLines.Any(l => l.Contains("<returns>")))
|
|
score += 15;
|
|
}
|
|
|
|
// Score for examples
|
|
if (suggestion.DocumentationLines.Any(l => l.Contains("<example>")))
|
|
score += 10;
|
|
|
|
// Score for exception documentation
|
|
if (suggestion.DocumentationLines.Any(l => l.Contains("<exception")))
|
|
score += 10;
|
|
|
|
return Math.Min(100, score);
|
|
}
|
|
|
|
private object CalculateDocumentationStats(List<EnhancedDocumentationSuggestion> suggestions, EnhancedCodeAnalysis analysis)
|
|
{
|
|
var totalLines = suggestions.Sum(s => s.DocumentationLines.Count);
|
|
var averageQuality = suggestions.Any() ? suggestions.Average(s => s.QualityScore) : 0;
|
|
|
|
var typeBreakdown = suggestions
|
|
.GroupBy(s => s.Member.Type)
|
|
.ToDictionary(g => g.Key, g => g.Count());
|
|
|
|
return new
|
|
{
|
|
TotalMembersDocumented = suggestions.Count,
|
|
TotalDocumentationLines = totalLines,
|
|
AverageQualityScore = Math.Round(averageQuality, 1),
|
|
TypeBreakdown = typeBreakdown,
|
|
CoveragePercentage = analysis.TotalMembers > 0
|
|
? Math.Round((double)suggestions.Count / analysis.TotalMembers * 100, 1)
|
|
: 0
|
|
};
|
|
}
|
|
|
|
private string ApplyDocumentationToCode(string originalContent, List<EnhancedDocumentationSuggestion> suggestions)
|
|
{
|
|
var lines = originalContent.Split('\n').ToList();
|
|
|
|
// Sort by line number in reverse order to avoid line number shifting
|
|
foreach (var suggestion in suggestions.OrderByDescending(s => s.Member.LineNumber))
|
|
{
|
|
var insertIndex = suggestion.Member.LineNumber - 1; // Convert to 0-based index
|
|
|
|
// Insert documentation lines before the member
|
|
for (int i = suggestion.DocumentationLines.Count - 1; i >= 0; i--)
|
|
{
|
|
lines.Insert(insertIndex, suggestion.DocumentationLines[i]);
|
|
}
|
|
}
|
|
|
|
return string.Join('\n', lines);
|
|
}
|
|
|
|
// Helper methods for parsing and analysis
|
|
private HashSet<string> GetAccessibilityFilter(string scope)
|
|
{
|
|
return scope.ToLower() switch
|
|
{
|
|
"public" => new HashSet<string> { "public" },
|
|
"protected" => new HashSet<string> { "public", "protected" },
|
|
"internal" => new HashSet<string> { "public", "protected", "internal" },
|
|
"all" => new HashSet<string> { "public", "protected", "internal", "private" },
|
|
_ => new HashSet<string> { "public" }
|
|
};
|
|
}
|
|
|
|
private bool ShouldDocumentMember(SyntaxNode node, HashSet<string> accessibilityFilter)
|
|
{
|
|
if (node is MemberDeclarationSyntax member)
|
|
{
|
|
var accessibility = GetAccessibility(member.Modifiers);
|
|
return accessibilityFilter.Contains(accessibility);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private string GetAccessibility(SyntaxTokenList modifiers)
|
|
{
|
|
if (modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)))
|
|
return "public";
|
|
else if (modifiers.Any(m => m.IsKind(SyntaxKind.ProtectedKeyword)))
|
|
return "protected";
|
|
else if (modifiers.Any(m => m.IsKind(SyntaxKind.InternalKeyword)))
|
|
return "internal";
|
|
else if (modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword)))
|
|
return "private";
|
|
else
|
|
return "private"; // Default accessibility
|
|
}
|
|
|
|
private bool HasDocumentation(SyntaxNode node)
|
|
{
|
|
return node.GetLeadingTrivia()
|
|
.Any(trivia => trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ||
|
|
trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia));
|
|
}
|
|
|
|
private int GetIndentLevel(SyntaxNode node)
|
|
{
|
|
var og = node.GetText().Lines.FirstOrDefault();
|
|
var text = (og == null) ? "" : og.ToString();
|
|
int count = 0;
|
|
foreach (char c in text)
|
|
{
|
|
if (c == '\t') count++;
|
|
else if (c != ' ') break;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private List<ParameterInfo> ExtractParameters(ParameterListSyntax parameterList)
|
|
{
|
|
return parameterList.Parameters.Select(p => new ParameterInfo
|
|
{
|
|
Name = p.Identifier.ValueText,
|
|
Type = p.Type.ToString(),
|
|
HasDefaultValue = p.Default != null,
|
|
DefaultValue = p.Default?.Value?.ToString()
|
|
}).ToList();
|
|
}
|
|
|
|
private string SplitCamelCase(string input)
|
|
{
|
|
return Regex.Replace(input, "([A-Z])", " $1").Trim();
|
|
}
|
|
|
|
private List<string> AnalyzeMethodUsage(MethodDeclarationSyntax method)
|
|
{
|
|
var patterns = new List<string>();
|
|
|
|
// Look for common patterns in method body
|
|
var methodBody = method.Body?.ToString() ?? "";
|
|
|
|
if (methodBody.Contains("for") || methodBody.Contains("foreach") || methodBody.Contains("while"))
|
|
patterns.Add("loop");
|
|
if (methodBody.Contains("await"))
|
|
patterns.Add("async");
|
|
if (methodBody.Contains("try") || methodBody.Contains("catch"))
|
|
patterns.Add("exception_handling");
|
|
if (methodBody.Contains("File.") || methodBody.Contains("Directory."))
|
|
patterns.Add("file_io");
|
|
if (methodBody.Contains("HttpClient") || methodBody.Contains("WebRequest"))
|
|
patterns.Add("web_request");
|
|
|
|
return patterns;
|
|
}
|
|
|
|
private int CalculateMethodComplexity(MethodDeclarationSyntax method)
|
|
{
|
|
int complexity = 1; // Base complexity
|
|
|
|
var decisionNodes = method.DescendantNodes().Where(node =>
|
|
node.IsKind(SyntaxKind.IfStatement) ||
|
|
node.IsKind(SyntaxKind.WhileStatement) ||
|
|
node.IsKind(SyntaxKind.ForStatement) ||
|
|
node.IsKind(SyntaxKind.ForEachStatement) ||
|
|
node.IsKind(SyntaxKind.SwitchStatement) ||
|
|
node.IsKind(SyntaxKind.CatchClause)
|
|
);
|
|
|
|
complexity += decisionNodes.Count();
|
|
return complexity;
|
|
}
|
|
}
|
|
|
|
// Supporting classes for enhanced documentation
|
|
public class EnhancedCodeAnalysis
|
|
{
|
|
public string FilePath { get; set; }
|
|
public List<EnhancedCodeMember> MembersNeedingDocumentation { get; set; } = new List<EnhancedCodeMember>();
|
|
public int TotalMembers { get; set; }
|
|
}
|
|
|
|
public class EnhancedCodeMember
|
|
{
|
|
public string Type { get; set; }
|
|
public string Name { get; set; }
|
|
public int LineNumber { get; set; }
|
|
public string OriginalLine { get; set; }
|
|
public int IndentLevel { get; set; }
|
|
public string Accessibility { get; set; }
|
|
public bool IsStatic { get; set; }
|
|
public bool IsAbstract { get; set; }
|
|
public bool IsAsync { get; set; }
|
|
public bool IsOverride { get; set; }
|
|
public bool IsVirtual { get; set; }
|
|
public bool HasGetter { get; set; }
|
|
public bool HasSetter { get; set; }
|
|
public List<string> BaseTypes { get; set; } = new List<string>();
|
|
public List<ParameterInfo> Parameters { get; set; } = new List<ParameterInfo>();
|
|
public string ReturnType { get; set; }
|
|
public MemberContext Context { get; set; }
|
|
}
|
|
|
|
public class MemberContext
|
|
{
|
|
public string ContainingTypeName { get; set; }
|
|
public string Namespace { get; set; }
|
|
public List<string> UsagePatterns { get; set; } = new List<string>();
|
|
public int ComplexityScore { get; set; }
|
|
}
|
|
|
|
public class EnhancedDocumentationSuggestion
|
|
{
|
|
public EnhancedCodeMember Member { get; set; }
|
|
public List<string> DocumentationLines { get; set; } = new List<string>();
|
|
public double QualityScore { get; set; }
|
|
}
|
|
|
|
public class ExceptionDocumentation
|
|
{
|
|
public string Type { get; set; }
|
|
public string Description { get; set; }
|
|
}
|
|
} |