using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Refactoring.Plugins { // Service for analyzing code structure public interface ICodeAnalysisService { Task AnalyzeComplexityAsync(SyntaxTree syntaxTree); Task> ExtractMethodsAsync(SyntaxTree syntaxTree); Task> ExtractClassesAsync(SyntaxTree syntaxTree); Task CalculateQualityMetricsAsync(SyntaxTree syntaxTree); } // Service for generating documentation templates public interface IDocumentationTemplateService { string GenerateClassDocumentation(ClassInfo classInfo, DocumentationOptions options); string GenerateMethodDocumentation(MethodInfo methodInfo, DocumentationOptions options); string GeneratePropertyDocumentation(PropertyInfo propertyInfo, DocumentationOptions options); string GenerateFileHeader(string fileName, DocumentationOptions options); } // Service for AI integration public interface IAIIntegrationService { Task GenerateIntelligentDescriptionAsync(string codeContext, string apiKey); Task> SuggestImprovementsAsync(string codeContext, string apiKey); Task GenerateExampleUsageAsync(string methodSignature, string apiKey); } // Service for formatting documentation public interface IDocumentationFormatter { string FormatAsXmlDocumentation(string content); string FormatAsMarkdown(string content); string FormatAsPlainText(string content); string ApplyCodeFormattingRules(string content, FormattingStyle style); } // Data structures public class CodeComplexityAnalysis { public int CyclomaticComplexity { get; set; } public int LinesOfCode { get; set; } public int NumberOfMethods { get; set; } public int NumberOfClasses { get; set; } public double MaintainabilityIndex { get; set; } public List Hotspots { get; set; } = new(); } public class ComplexityHotspot { public string Name { get; set; } public int Complexity { get; set; } public int LineNumber { get; set; } public string Reason { get; set; } } public class MethodInfo { public string Name { get; set; } public string ReturnType { get; set; } public List Parameters { get; set; } = new(); public string AccessModifier { get; set; } public bool IsStatic { get; set; } public bool IsAsync { get; set; } public int LineNumber { get; set; } public int CyclomaticComplexity { get; set; } public string ExistingDocumentation { get; set; } } public class ClassInfo { public string Name { get; set; } public string Namespace { get; set; } public string AccessModifier { get; set; } public bool IsAbstract { get; set; } public bool IsStatic { get; set; } public List Interfaces { get; set; } = new(); public string BaseClass { get; set; } public List Methods { get; set; } = new(); public List Properties { get; set; } = new(); public int LineNumber { get; set; } public string ExistingDocumentation { get; set; } } public class PropertyInfo { public string Name { get; set; } public string Type { get; set; } public string AccessModifier { get; set; } public bool HasGetter { get; set; } public bool HasSetter { get; set; } public bool IsStatic { get; set; } public int LineNumber { get; set; } public string ExistingDocumentation { get; set; } } public class ParameterInfo { public string Name { get; set; } public string Type { get; set; } public bool HasDefaultValue { get; set; } public string DefaultValue { get; set; } public bool IsParams { get; set; } } public class QualityMetrics { public double CohesionScore { get; set; } public double CouplingScore { get; set; } public double ComplexityScore { get; set; } public double DocumentationCoverage { get; set; } public int CodeSmells { get; set; } public List Suggestions { get; set; } = new(); } public class DocumentationOptions { public bool IncludeParameters { get; set; } = true; public bool IncludeReturns { get; set; } = true; public bool IncludeExceptions { get; set; } = true; public bool IncludeExamples { get; set; } = false; public bool IncludeRemarks { get; set; } = false; public bool GenerateAIDescriptions { get; set; } = false; public DocumentationStyle Style { get; set; } = DocumentationStyle.Standard; public string Author { get; set; } = "Generated"; public DateTime CreatedDate { get; set; } = DateTime.UtcNow; } public enum DocumentationStyle { Standard, Detailed, Minimal, Enterprise } public enum FormattingStyle { Microsoft, Allman, KAndR, Google } // Concrete implementations public class CodeAnalysisService : ICodeAnalysisService { public async Task AnalyzeComplexityAsync(SyntaxTree syntaxTree) { var root = await syntaxTree.GetRootAsync(); var analysis = new CodeComplexityAnalysis(); // Count methods and classes var methods = root.DescendantNodes().OfType().ToList(); var classes = root.DescendantNodes().OfType().ToList(); analysis.NumberOfMethods = methods.Count; analysis.NumberOfClasses = classes.Count; analysis.LinesOfCode = syntaxTree.GetText().Lines.Count; // Calculate cyclomatic complexity foreach (var method in methods) { var complexity = CalculateMethodComplexity(method); analysis.CyclomaticComplexity += complexity; if (complexity > 10) { analysis.Hotspots.Add(new ComplexityHotspot { Name = method.Identifier.ValueText, Complexity = complexity, LineNumber = method.GetLocation().GetLineSpan().StartLinePosition.Line + 1, Reason = "High cyclomatic complexity" }); } } // Calculate maintainability index (simplified) analysis.MaintainabilityIndex = CalculateMaintainabilityIndex(analysis); return analysis; } public async Task> ExtractMethodsAsync(SyntaxTree syntaxTree) { var root = await syntaxTree.GetRootAsync(); var methods = new List(); foreach (var method in root.DescendantNodes().OfType()) { var methodInfo = new MethodInfo { Name = method.Identifier.ValueText, ReturnType = method.ReturnType.ToString(), AccessModifier = GetAccessModifier(method.Modifiers), IsStatic = method.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)), IsAsync = method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)), LineNumber = method.GetLocation().GetLineSpan().StartLinePosition.Line + 1, CyclomaticComplexity = CalculateMethodComplexity(method), ExistingDocumentation = ExtractDocumentation(method) }; // Extract parameters foreach (var param in method.ParameterList.Parameters) { methodInfo.Parameters.Add(new ParameterInfo { Name = param.Identifier.ValueText, Type = param.Type?.ToString() ?? "unknown", HasDefaultValue = param.Default != null, DefaultValue = param.Default?.Value?.ToString(), IsParams = param.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword)) }); } methods.Add(methodInfo); } return methods; } public async Task> ExtractClassesAsync(SyntaxTree syntaxTree) { var root = await syntaxTree.GetRootAsync(); var classes = new List(); foreach (var classDeclaration in root.DescendantNodes().OfType()) { var classInfo = new ClassInfo { Name = classDeclaration.Identifier.ValueText, Namespace = GetNamespace(classDeclaration), AccessModifier = GetAccessModifier(classDeclaration.Modifiers), IsAbstract = classDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword)), IsStatic = classDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)), LineNumber = classDeclaration.GetLocation().GetLineSpan().StartLinePosition.Line + 1, ExistingDocumentation = ExtractDocumentation(classDeclaration) }; // Extract base class and interfaces if (classDeclaration.BaseList != null) { foreach (var baseType in classDeclaration.BaseList.Types) { var typeName = baseType.Type.ToString(); if (baseType.Type is IdentifierNameSyntax && char.IsUpper(typeName[0])) { if (classInfo.BaseClass == null) classInfo.BaseClass = typeName; else classInfo.Interfaces.Add(typeName); } else { classInfo.Interfaces.Add(typeName); } } } classes.Add(classInfo); } return classes; } public async Task CalculateQualityMetricsAsync(SyntaxTree syntaxTree) { var analysis = await AnalyzeComplexityAsync(syntaxTree); var methods = await ExtractMethodsAsync(syntaxTree); var classes = await ExtractClassesAsync(syntaxTree); var metrics = new QualityMetrics(); // Calculate documentation coverage var documntedMethods = methods.Count(m => !string.IsNullOrEmpty(m.ExistingDocumentation)); var documentedClasses = classes.Count(c => !string.IsNullOrEmpty(c.ExistingDocumentation)); if (methods.Count + classes.Count > 0) { metrics.DocumentationCoverage = (double)(documntedMethods + documentedClasses) / (methods.Count + classes.Count); } // Calculate complexity score (normalized) metrics.ComplexityScore = Math.Min(1.0, analysis.CyclomaticComplexity / 100.0); // Identify code smells metrics.CodeSmells = analysis.Hotspots.Count; metrics.CodeSmells += methods.Count(m => m.Parameters.Count > 5); // Too many parameters metrics.CodeSmells += classes.Count(c => c.Methods.Count > 20); // God classes // Generate suggestions if (metrics.DocumentationCoverage < 0.5) metrics.Suggestions.Add("Consider adding more documentation to improve code maintainability"); if (analysis.Hotspots.Any()) metrics.Suggestions.Add("Some methods have high complexity and could benefit from refactoring"); return metrics; } private int CalculateMethodComplexity(MethodDeclarationSyntax method) { int complexity = 1; // Base complexity // Count decision points 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) || node.IsKind(SyntaxKind.ConditionalExpression)); complexity += decisionNodes.Count(); return complexity; } private double CalculateMaintainabilityIndex(CodeComplexityAnalysis analysis) { // Simplified maintainability index calculation var volume = analysis.LinesOfCode * Math.Log2(Math.Max(1, analysis.NumberOfMethods)); var complexity = Math.Max(1, analysis.CyclomaticComplexity); return Math.Max(0, (171 - 5.2 * Math.Log(volume) - 0.23 * complexity - 16.2 * Math.Log(analysis.LinesOfCode)) * 100 / 171); } private string GetAccessModifier(SyntaxTokenList modifiers) { if (modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) return "public"; if (modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) return "private"; if (modifiers.Any(m => m.IsKind(SyntaxKind.ProtectedKeyword))) return "protected"; if (modifiers.Any(m => m.IsKind(SyntaxKind.InternalKeyword))) return "internal"; return "private"; // Default in C# } private string GetNamespace(SyntaxNode node) { var namespaceDeclaration = node.Ancestors().OfType().FirstOrDefault(); return namespaceDeclaration?.Name?.ToString() ?? ""; } private string ExtractDocumentation(SyntaxNode node) { var documentationComment = node.GetLeadingTrivia() .FirstOrDefault(t => t.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || t.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)); return documentationComment.ToString().Trim(); } } public class DocumentationTemplateService : IDocumentationTemplateService { public string GenerateClassDocumentation(ClassInfo classInfo, DocumentationOptions options) { var sb = new StringBuilder(); sb.AppendLine("/// "); sb.AppendLine($"/// Represents a {classInfo.Name} class."); sb.AppendLine("/// "); if (options.IncludeRemarks) { sb.AppendLine("/// "); sb.AppendLine($"/// This class contains {classInfo.Methods.Count} methods and {classInfo.Properties.Count} properties."); sb.AppendLine("/// "); } return sb.ToString(); } public string GenerateMethodDocumentation(MethodInfo methodInfo, DocumentationOptions options) { var sb = new StringBuilder(); sb.AppendLine("/// "); sb.AppendLine($"/// {GenerateMethodDescription(methodInfo)}"); sb.AppendLine("/// "); if (options.IncludeParameters && methodInfo.Parameters.Any()) { foreach (var param in methodInfo.Parameters) { sb.AppendLine($"/// The {param.Name} parameter."); } } if (options.IncludeReturns && methodInfo.ReturnType != "void") { sb.AppendLine($"/// Returns a {methodInfo.ReturnType}."); } return sb.ToString(); } public string GeneratePropertyDocumentation(PropertyInfo propertyInfo, DocumentationOptions options) { var sb = new StringBuilder(); sb.AppendLine("/// "); sb.AppendLine($"/// Gets or sets the {propertyInfo.Name}."); sb.AppendLine("/// "); return sb.ToString(); } public string GenerateFileHeader(string fileName, DocumentationOptions options) { var sb = new StringBuilder(); sb.AppendLine("/*"); sb.AppendLine($" * File: {fileName}"); sb.AppendLine($" * Generated: {options.CreatedDate:yyyy-MM-dd HH:mm:ss}"); sb.AppendLine($" * Author: {options.Author}"); sb.AppendLine(" */"); sb.AppendLine(); return sb.ToString(); } private string GenerateMethodDescription(MethodInfo methodInfo) { if (methodInfo.Name.StartsWith("Get")) return $"Gets {methodInfo.Name.Substring(3).ToLowerInvariant()} information."; if (methodInfo.Name.StartsWith("Set")) return $"Sets {methodInfo.Name.Substring(3).ToLowerInvariant()} information."; if (methodInfo.Name.StartsWith("Create")) return $"Creates a new {methodInfo.Name.Substring(6).ToLowerInvariant()}."; if (methodInfo.Name.StartsWith("Delete")) return $"Deletes the specified {methodInfo.Name.Substring(6).ToLowerInvariant()}."; if (methodInfo.Name.StartsWith("Update")) return $"Updates the specified {methodInfo.Name.Substring(6).ToLowerInvariant()}."; return $"Executes the {methodInfo.Name} operation."; } } }