MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Refacto.../EnhancedDocumentationGenera...

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; }
}
}