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.RegularExpressions; using System.Threading.Tasks; namespace MarketAlly.AIPlugin.Refactoring.Plugins { [AIPlugin("NamingConvention", "Analyzes and suggests improvements for variable, method, and class naming")] public class NamingConventionPlugin : IAIPlugin { // Compiled regex patterns for performance private static readonly Regex SingleLetterPattern = new Regex(@"^[a-zA-Z]\d*$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex GenericNamesPattern = new Regex(@"^(temp|tmp|val|var|obj|item|data|info|str|num|cnt|idx|len)\d*$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex ShortAbbrevPattern = new Regex(@"^[a-zA-Z]{1,2}$", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex HungarianPattern = new Regex(@"^(str|int|bool|obj|lst|arr|dict)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex ConsecutiveUnderscoresPattern = new Regex(@"_{2,}", RegexOptions.Compiled); private static readonly Regex ConsecutiveCapitalsPattern = new Regex(@"[A-Z]{3,}", RegexOptions.Compiled); private static readonly Regex NonAlphaNumericPattern = new Regex(@"[^a-zA-Z0-9_]", RegexOptions.Compiled); private static readonly Regex DigitStartPattern = new Regex(@"^\d", RegexOptions.Compiled); private static readonly Regex ExcessiveWordsPattern = new Regex(@"(\b\w+\b.*){8,}", RegexOptions.Compiled); private static readonly Regex ReservedKeywordsPattern = new Regex(@"^(abstract|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); [AIParameter("Full path to the file to analyze", required: true)] public string FilePath { get; set; } [AIParameter("Naming convention: pascal, camel, snake, kebab", required: false)] public string Convention { get; set; } = "pascal"; [AIParameter("Check for meaningful names", required: false)] public bool CheckMeaningfulness { get; set; } = true; [AIParameter("Suggest better names using AI", required: false)] public bool AISuggestions { get; set; } = true; [AIParameter("Apply naming changes to file", required: false)] public bool ApplyChanges { get; set; } = false; [AIParameter("Minimum length for meaningful names", required: false)] public int MinimumNameLength { get; set; } = 3; [AIParameter("Check abbreviations and acronyms", required: false)] public bool CheckAbbreviations { get; set; } = true; public IReadOnlyDictionary SupportedParameters => new Dictionary { ["filePath"] = typeof(string), ["filepath"] = typeof(string), // Allow lowercase ["convention"] = typeof(string), ["checkMeaningfulness"] = typeof(bool), ["checkmeaningfulness"] = typeof(bool), // Allow lowercase ["aiSuggestions"] = typeof(bool), ["aisuggestions"] = typeof(bool), // Allow lowercase ["applyChanges"] = typeof(bool), ["applychanges"] = typeof(bool), // Allow lowercase ["minimumNameLength"] = typeof(int), ["minimumnamelength"] = typeof(int), // Allow lowercase ["checkAbbreviations"] = typeof(bool), ["checkabbreviations"] = typeof(bool) // Allow lowercase }; public async Task ExecuteAsync(IReadOnlyDictionary parameters) { try { // Extract parameters with case-insensitive handling string filePath = GetParameterValue(parameters, "filePath", "filepath")?.ToString(); string convention = GetParameterValue(parameters, "convention")?.ToString()?.ToLower() ?? "pascal"; bool checkMeaningfulness = GetBoolParameter(parameters, "checkMeaningfulness", "checkmeaningfulness", true); bool aiSuggestions = GetBoolParameter(parameters, "aiSuggestions", "aisuggestions", true); bool applyChanges = GetBoolParameter(parameters, "applyChanges", "applychanges", false); int minimumNameLength = GetIntParameter(parameters, "minimumNameLength", "minimumnamelength", 3); bool checkAbbreviations = GetBoolParameter(parameters, "checkAbbreviations", "checkabbreviations", true); // 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 naming conventions var namingAnalysis = await AnalyzeNamingConventions(root, filePath, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); // Generate AI-powered suggestions if requested if (aiSuggestions && namingAnalysis.Issues.Any()) { await GenerateAISuggestions(namingAnalysis); } // Apply changes if requested if (applyChanges && namingAnalysis.Suggestions.Any(s => s.ShouldApply)) { var modifiedContent = await ApplyNamingChanges(sourceCode, namingAnalysis); // Create backup var backupPath = $"{filePath}.{DateTime.Now:yyyyMMdd_HHmmss}.bak"; File.Copy(filePath, backupPath); // Write modified content await File.WriteAllTextAsync(filePath, modifiedContent); return new AIPluginResult(new { Message = $"Applied {namingAnalysis.Suggestions.Count(s => s.ShouldApply)} naming improvements", FilePath = filePath, BackupPath = backupPath, Convention = convention, ChangesApplied = true, Analysis = namingAnalysis, ModifiedContent = modifiedContent, Timestamp = DateTime.UtcNow }); } else { return new AIPluginResult(new { Message = $"Found {namingAnalysis.Issues.Count} naming issues with {namingAnalysis.Suggestions.Count} suggestions", FilePath = filePath, Convention = convention, ChangesApplied = false, Analysis = namingAnalysis, Timestamp = DateTime.UtcNow }); } } catch (Exception ex) { return new AIPluginResult(ex, $"Naming convention analysis failed: {ex.Message}"); } } private async Task AnalyzeNamingConventions(SyntaxNode root, string filePath, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var analysis = new NamingAnalysis { FilePath = filePath, Convention = convention, Issues = new List(), Suggestions = new List() }; // Analyze different types of identifiers await AnalyzeClasses(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeInterfaces(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeMethods(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeProperties(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeFields(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeParameters(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); await AnalyzeLocalVariables(root, analysis, convention, checkMeaningfulness, checkAbbreviations, minimumNameLength); // Calculate statistics analysis.Statistics = CalculateNamingStatistics(analysis); return analysis; } private async Task AnalyzeClasses(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var classes = root.DescendantNodes().OfType(); foreach (var cls in classes) { var name = cls.Identifier.ValueText; var lineNumber = cls.GetLocation().GetLineSpan().StartLinePosition.Line + 1; await AnalyzeIdentifier(analysis, "Class", name, lineNumber, "PascalCase", checkMeaningfulness, checkAbbreviations, minimumNameLength); } } private async Task AnalyzeInterfaces(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var interfaces = root.DescendantNodes().OfType(); foreach (var iface in interfaces) { var name = iface.Identifier.ValueText; var lineNumber = iface.GetLocation().GetLineSpan().StartLinePosition.Line + 1; // Interfaces should start with 'I' and use PascalCase var issues = new List(); if (!name.StartsWith("I") || !char.IsUpper(name, 1)) { issues.Add("Interface names should start with 'I' followed by PascalCase"); } await AnalyzeIdentifier(analysis, "Interface", name, lineNumber, "IPascalCase", checkMeaningfulness, checkAbbreviations, minimumNameLength, issues); } } private async Task AnalyzeMethods(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var methods = root.DescendantNodes().OfType(); foreach (var method in methods) { var name = method.Identifier.ValueText; var lineNumber = method.GetLocation().GetLineSpan().StartLinePosition.Line + 1; await AnalyzeIdentifier(analysis, "Method", name, lineNumber, "PascalCase", checkMeaningfulness, checkAbbreviations, minimumNameLength); } } private async Task AnalyzeProperties(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var properties = root.DescendantNodes().OfType(); foreach (var property in properties) { var name = property.Identifier.ValueText; var lineNumber = property.GetLocation().GetLineSpan().StartLinePosition.Line + 1; await AnalyzeIdentifier(analysis, "Property", name, lineNumber, "PascalCase", checkMeaningfulness, checkAbbreviations, minimumNameLength); } } private async Task AnalyzeFields(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var fields = root.DescendantNodes().OfType(); foreach (var field in fields) { foreach (var variable in field.Declaration.Variables) { var name = variable.Identifier.ValueText; var lineNumber = field.GetLocation().GetLineSpan().StartLinePosition.Line + 1; // Check if it's a private field (should use camelCase or _camelCase) var isPrivate = field.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword)) || !field.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword) || m.IsKind(SyntaxKind.ProtectedKeyword) || m.IsKind(SyntaxKind.InternalKeyword)); var expectedConvention = isPrivate ? "camelCase" : "PascalCase"; await AnalyzeIdentifier(analysis, "Field", name, lineNumber, expectedConvention, checkMeaningfulness, checkAbbreviations, minimumNameLength); } } } private async Task AnalyzeParameters(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var methods = root.DescendantNodes().OfType(); foreach (var method in methods) { foreach (var parameter in method.ParameterList.Parameters) { var name = parameter.Identifier.ValueText; var lineNumber = parameter.GetLocation().GetLineSpan().StartLinePosition.Line + 1; await AnalyzeIdentifier(analysis, "Parameter", name, lineNumber, "camelCase", checkMeaningfulness, checkAbbreviations, minimumNameLength); } } } private async Task AnalyzeLocalVariables(SyntaxNode root, NamingAnalysis analysis, string convention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength) { var variableDeclarations = root.DescendantNodes().OfType(); foreach (var declaration in variableDeclarations) { // Skip field declarations (already handled) if (declaration.Parent is FieldDeclarationSyntax) continue; foreach (var variable in declaration.Variables) { var name = variable.Identifier.ValueText; var lineNumber = declaration.GetLocation().GetLineSpan().StartLinePosition.Line + 1; await AnalyzeIdentifier(analysis, "Variable", name, lineNumber, "camelCase", checkMeaningfulness, checkAbbreviations, minimumNameLength); } } } private async Task AnalyzeIdentifier(NamingAnalysis analysis, string identifierType, string name, int lineNumber, string expectedConvention, bool checkMeaningfulness, bool checkAbbreviations, int minimumNameLength, List additionalIssues = null) { var issues = new List(); if (additionalIssues != null) issues.AddRange(additionalIssues); // Check naming convention if (!IsValidConvention(name, expectedConvention)) { issues.Add($"Should follow {expectedConvention} convention"); } // Check meaningful names if (checkMeaningfulness) { var meaningfulnessIssues = CheckMeaningfulnessMethod(name, identifierType, minimumNameLength); issues.AddRange(meaningfulnessIssues); } // Check abbreviations if (checkAbbreviations) { var abbreviationIssues = CheckAbbreviationsMethod(name, identifierType); issues.AddRange(abbreviationIssues); } // Create issue if any problems found if (issues.Any()) { var issue = new NamingIssue { IdentifierType = identifierType, Name = name, LineNumber = lineNumber, Issues = issues, Severity = CalculateSeverity(issues) }; analysis.Issues.Add(issue); // Generate suggestion var suggestion = await GenerateNamingSuggestion(issue, expectedConvention); if (suggestion != null) { analysis.Suggestions.Add(suggestion); } } } private bool IsValidConvention(string name, string convention) { switch (convention.ToLower()) { case "pascalcase": return IsPascalCase(name); case "camelcase": return IsCamelCase(name); case "ipascalcase": // Interface naming return name.StartsWith("I") && name.Length > 1 && IsPascalCase(name.Substring(1)); case "snake": case "snake_case": return IsSnakeCase(name); case "kebab": case "kebab-case": return IsKebabCase(name); default: return true; // Unknown convention, assume valid } } private bool IsPascalCase(string name) { if (string.IsNullOrEmpty(name)) return false; return char.IsUpper(name[0]) && !name.Contains('_') && !name.Contains('-'); } private bool IsCamelCase(string name) { if (string.IsNullOrEmpty(name)) return false; // Allow underscore prefix for private fields if (name.StartsWith("_")) name = name.Substring(1); return char.IsLower(name[0]) && !name.Contains('_') && !name.Contains('-'); } private bool IsSnakeCase(string name) { return !string.IsNullOrEmpty(name) && name.All(c => char.IsLower(c) || char.IsDigit(c) || c == '_') && !name.StartsWith("_") && !name.EndsWith("_"); } private bool IsKebabCase(string name) { return !string.IsNullOrEmpty(name) && name.All(c => char.IsLower(c) || char.IsDigit(c) || c == '-') && !name.StartsWith("-") && !name.EndsWith("-"); } private List CheckMeaningfulnessMethod(string name, string identifierType, int minimumLength) { var issues = new List(); // Check length if (name.Length < minimumLength) { issues.Add($"Name is too short (minimum {minimumLength} characters)"); } // Check for non-meaningful names using compiled patterns if (SingleLetterPattern.IsMatch(name)) { issues.Add("Name is not descriptive enough"); } else if (GenericNamesPattern.IsMatch(name)) { issues.Add("Name is not descriptive enough"); } else if (ShortAbbrevPattern.IsMatch(name)) { issues.Add("Name is not descriptive enough"); } // Check for Hungarian notation (discouraged in modern C#) using compiled pattern if (HungarianPattern.IsMatch(name)) { issues.Add("Avoid Hungarian notation in modern C#"); } return issues; } private List CheckAbbreviationsMethod(string name, string identifierType) { var issues = new List(); // Common abbreviations that should be spelled out var discouragedAbbreviations = new Dictionary { ["btn"] = "button", ["lbl"] = "label", ["txt"] = "text", ["img"] = "image", ["pic"] = "picture", ["doc"] = "document", ["docs"] = "documents", ["config"] = "configuration", ["info"] = "information", ["admin"] = "administrator", ["auth"] = "authentication", ["repo"] = "repository", ["util"] = "utility", ["mgr"] = "manager", ["svc"] = "service", ["ctx"] = "context", ["args"] = "arguments", ["params"] = "parameters", ["req"] = "request", ["res"] = "response", ["resp"] = "response" }; var lowerName = name.ToLower(); foreach (var abbrev in discouragedAbbreviations) { if (lowerName.Contains(abbrev.Key)) { issues.Add($"Consider spelling out abbreviation '{abbrev.Key}' as '{abbrev.Value}'"); break; } } // Check for excessive acronyms var acronymCount = Regex.Matches(name, @"[A-Z]{2,}").Count; if (acronymCount > 1) { issues.Add("Too many acronyms, consider more descriptive naming"); } return issues; } private string CalculateSeverity(List issues) { if (issues.Any(i => i.Contains("not descriptive") || i.Contains("too short"))) return "High"; else if (issues.Any(i => i.Contains("convention") || i.Contains("Hungarian"))) return "Medium"; else return "Low"; } private async Task GenerateNamingSuggestion(NamingIssue issue, string expectedConvention) { var suggestion = new NamingSuggestion { OriginalName = issue.Name, IdentifierType = issue.IdentifierType, LineNumber = issue.LineNumber, Issues = issue.Issues, SuggestedNames = new List(), Confidence = 0.0, Reasoning = new List() }; // Generate suggestions based on the issues await GenerateConventionSuggestions(suggestion, expectedConvention); await GenerateMeaningfulnessSuggestions(suggestion); await GenerateAbbreviationSuggestions(suggestion); // Calculate overall confidence suggestion.Confidence = CalculateSuggestionConfidence(suggestion); suggestion.ShouldApply = suggestion.Confidence > 0.8 && suggestion.SuggestedNames.Any(); return suggestion.SuggestedNames.Any() ? suggestion : null; } private async Task GenerateConventionSuggestions(NamingSuggestion suggestion, string expectedConvention) { var name = suggestion.OriginalName; if (suggestion.Issues.Any(i => i.Contains("convention"))) { var convertedName = ConvertToConvention(name, expectedConvention); if (convertedName != name) { suggestion.SuggestedNames.Add(convertedName); suggestion.Reasoning.Add($"Converted to {expectedConvention} convention"); } } await Task.CompletedTask; } private async Task GenerateMeaningfulnessSuggestions(NamingSuggestion suggestion) { var name = suggestion.OriginalName; if (suggestion.Issues.Any(i => i.Contains("not descriptive") || i.Contains("too short"))) { var meaningfulSuggestions = GenerateMeaningfulAlternatives(name, suggestion.IdentifierType); suggestion.SuggestedNames.AddRange(meaningfulSuggestions); if (meaningfulSuggestions.Any()) { suggestion.Reasoning.Add("Generated more descriptive alternatives"); } } await Task.CompletedTask; } private async Task GenerateAbbreviationSuggestions(NamingSuggestion suggestion) { var name = suggestion.OriginalName; if (suggestion.Issues.Any(i => i.Contains("abbreviation"))) { var expandedName = ExpandAbbreviations(name); if (expandedName != name) { suggestion.SuggestedNames.Add(expandedName); suggestion.Reasoning.Add("Expanded abbreviations for clarity"); } } await Task.CompletedTask; } private string ConvertToConvention(string name, string convention) { switch (convention.ToLower()) { case "pascalcase": return ToPascalCase(name); case "camelcase": return ToCamelCase(name); case "ipascalcase": return name.StartsWith("I") ? name : "I" + ToPascalCase(name); case "snake_case": return ToSnakeCase(name); case "kebab-case": return ToKebabCase(name); default: return name; } } private string ToPascalCase(string name) { if (string.IsNullOrEmpty(name)) return name; // Handle underscore-separated names if (name.Contains('_')) { var parts = name.Split('_', StringSplitOptions.RemoveEmptyEntries); return string.Join("", parts.Select(p => char.ToUpper(p[0]) + p.Substring(1).ToLower())); } // Handle kebab-case if (name.Contains('-')) { var parts = name.Split('-', StringSplitOptions.RemoveEmptyEntries); return string.Join("", parts.Select(p => char.ToUpper(p[0]) + p.Substring(1).ToLower())); } // Convert first character to uppercase return char.ToUpper(name[0]) + name.Substring(1); } private string ToCamelCase(string name) { // Remove leading underscore if present if (name.StartsWith("_")) name = name.Substring(1); var pascalCase = ToPascalCase(name); return char.ToLower(pascalCase[0]) + pascalCase.Substring(1); } private string ToSnakeCase(string name) { // Convert PascalCase/camelCase to snake_case var result = Regex.Replace(name, @"([a-z])([A-Z])", "$1_$2").ToLower(); return result.Replace("-", "_"); } private string ToKebabCase(string name) { // Convert PascalCase/camelCase to kebab-case var result = Regex.Replace(name, @"([a-z])([A-Z])", "$1-$2").ToLower(); return result.Replace("_", "-"); } private List GenerateMeaningfulAlternatives(string name, string identifierType) { var alternatives = new List(); // Context-based suggestions var contextSuggestions = GetContextualSuggestions(name, identifierType); alternatives.AddRange(contextSuggestions); // Pattern-based expansions var patternSuggestions = GetPatternBasedSuggestions(name, identifierType); alternatives.AddRange(patternSuggestions); return alternatives.Distinct().ToList(); } private List GetContextualSuggestions(string name, string identifierType) { var suggestions = new List(); // Common replacements for generic names var replacements = new Dictionary { ["i"] = new[] { "index", "iterator", "itemCount" }, ["j"] = new[] { "innerIndex", "columnIndex", "secondIndex" }, ["k"] = new[] { "keyIndex", "thirdIndex" }, ["x"] = new[] { "xCoordinate", "horizontalPosition", "width" }, ["y"] = new[] { "yCoordinate", "verticalPosition", "height" }, ["temp"] = new[] { "temporaryValue", "intermediateResult", "buffer" }, ["tmp"] = new[] { "temporary", "temporaryData", "tempResult" }, ["val"] = new[] { "value", "currentValue", "inputValue" }, ["var"] = new[] { "variable", "currentVariable", "localVariable" }, ["obj"] = new[] { "object", "instance", "entity" }, ["item"] = new[] { "currentItem", "selectedItem", "dataItem" }, ["data"] = new[] { "inputData", "userData", "responseData" }, ["info"] = new[] { "information", "details", "metadata" }, ["str"] = new[] { "text", "message", "content" }, ["num"] = new[] { "number", "count", "quantity" }, ["cnt"] = new[] { "count", "counter", "total" }, ["idx"] = new[] { "index", "position", "location" }, ["len"] = new[] { "length", "size", "count" } }; var lowerName = name.ToLower(); if (replacements.ContainsKey(lowerName)) { suggestions.AddRange(replacements[lowerName]); } return suggestions; } private List GetPatternBasedSuggestions(string name, string identifierType) { var suggestions = new List(); switch (identifierType.ToLower()) { case "method": if (name.Length <= 3) { suggestions.AddRange(new[] { "Execute", "Process", "Handle", "Perform", "Calculate" }); } break; case "property": if (name.Length <= 3) { suggestions.AddRange(new[] { "Value", "Name", "Title", "Description", "Status" }); } break; case "variable": case "parameter": if (name.Length <= 3) { suggestions.AddRange(new[] { "input", "output", "result", "value", "data" }); } break; } return suggestions; } private string ExpandAbbreviations(string name) { var expansions = new Dictionary { ["btn"] = "Button", ["lbl"] = "Label", ["txt"] = "Text", ["img"] = "Image", ["pic"] = "Picture", ["doc"] = "Document", ["config"] = "Configuration", ["info"] = "Information", ["admin"] = "Administrator", ["auth"] = "Authentication", ["repo"] = "Repository", ["util"] = "Utility", ["mgr"] = "Manager", ["svc"] = "Service", ["ctx"] = "Context", ["req"] = "Request", ["res"] = "Response", ["resp"] = "Response" }; var result = name; foreach (var expansion in expansions) { // Case-insensitive replacement while preserving original casing pattern var pattern = $@"\b{Regex.Escape(expansion.Key)}\b"; result = Regex.Replace(result, pattern, expansion.Value, RegexOptions.IgnoreCase); } return result; } private double CalculateSuggestionConfidence(NamingSuggestion suggestion) { double confidence = 0.5; // Base confidence // Higher confidence for clear convention fixes if (suggestion.Issues.Any(i => i.Contains("convention"))) confidence += 0.3; // Lower confidence for subjective meaningfulness issues if (suggestion.Issues.Any(i => i.Contains("not descriptive"))) confidence += 0.1; // Higher confidence for abbreviation expansions if (suggestion.Issues.Any(i => i.Contains("abbreviation"))) confidence += 0.2; // Adjust based on number of suggestions if (suggestion.SuggestedNames.Count == 1) confidence += 0.1; else if (suggestion.SuggestedNames.Count > 3) confidence -= 0.1; return Math.Min(1.0, confidence); } private async Task GenerateAISuggestions(NamingAnalysis analysis) { // This would integrate with an AI service to generate more sophisticated suggestions // For now, we'll enhance the existing suggestions with better reasoning foreach (var suggestion in analysis.Suggestions) { // Add AI-powered reasoning (simulated) if (suggestion.IdentifierType == "Method" && suggestion.OriginalName.Length <= 3) { suggestion.Reasoning.Add("AI Suggestion: Method names should describe the action being performed"); suggestion.SuggestedNames.Add($"Execute{suggestion.OriginalName.ToUpper()}Operation"); } if (suggestion.IdentifierType == "Class" && suggestion.OriginalName.Contains("_")) { suggestion.Reasoning.Add("AI Suggestion: Class names should use PascalCase without underscores"); } } await Task.CompletedTask; } private async Task ApplyNamingChanges(string sourceCode, NamingAnalysis analysis) { var modifiedContent = sourceCode; // Apply suggestions in reverse order of line numbers to maintain positions var applicableSuggestions = analysis.Suggestions .Where(s => s.ShouldApply && s.SuggestedNames.Any()) .OrderByDescending(s => s.LineNumber); foreach (var suggestion in applicableSuggestions) { var bestSuggestion = suggestion.SuggestedNames.First(); // Simple text replacement (in a real implementation, you'd use Roslyn for accurate renaming) modifiedContent = modifiedContent.Replace(suggestion.OriginalName, bestSuggestion); } return await Task.FromResult(modifiedContent); } private NamingStatistics CalculateNamingStatistics(NamingAnalysis analysis) { var stats = new NamingStatistics(); stats.TotalIdentifiers = analysis.Issues.Count; stats.ConventionViolations = analysis.Issues.Count(i => i.Issues.Any(iss => iss.Contains("convention"))); stats.MeaningfulnessIssues = analysis.Issues.Count(i => i.Issues.Any(iss => iss.Contains("descriptive") || iss.Contains("short"))); stats.AbbreviationIssues = analysis.Issues.Count(i => i.Issues.Any(iss => iss.Contains("abbreviation"))); stats.SeverityBreakdown = analysis.Issues .GroupBy(i => i.Severity) .ToDictionary(g => g.Key, g => g.Count()); stats.TypeBreakdown = analysis.Issues .GroupBy(i => i.IdentifierType) .ToDictionary(g => g.Key, g => g.Count()); stats.QualityScore = CalculateNamingQualityScore(analysis); return stats; } private double CalculateNamingQualityScore(NamingAnalysis analysis) { if (!analysis.Issues.Any()) return 100.0; double score = 100.0; // Penalize based on severity score -= analysis.Issues.Count(i => i.Severity == "High") * 10; score -= analysis.Issues.Count(i => i.Severity == "Medium") * 5; score -= analysis.Issues.Count(i => i.Severity == "Low") * 2; return Math.Max(0, score); } // Helper methods for parameter extraction private object GetParameterValue(IReadOnlyDictionary parameters, params string[] keys) { foreach (var key in keys) { if (parameters.TryGetValue(key, out var value)) return value; } return null; } private bool GetBoolParameter(IReadOnlyDictionary parameters, string key1, string key2, bool defaultValue = false) { var value = GetParameterValue(parameters, key1, key2); return value != null ? Convert.ToBoolean(value) : defaultValue; } private int GetIntParameter(IReadOnlyDictionary parameters, string key1, string key2, int defaultValue = 0) { var value = GetParameterValue(parameters, key1, key2); return value != null ? Convert.ToInt32(value) : defaultValue; } } // Supporting classes for naming analysis public class NamingAnalysis { public string FilePath { get; set; } public string Convention { get; set; } public List Issues { get; set; } = new List(); public List Suggestions { get; set; } = new List(); public NamingStatistics Statistics { get; set; } } public class NamingIssue { public string IdentifierType { get; set; } public string Name { get; set; } public int LineNumber { get; set; } public List Issues { get; set; } = new List(); public string Severity { get; set; } } public class NamingSuggestion { public string OriginalName { get; set; } public string IdentifierType { get; set; } public int LineNumber { get; set; } public List Issues { get; set; } = new List(); public List SuggestedNames { get; set; } = new List(); public List Reasoning { get; set; } = new List(); public double Confidence { get; set; } public bool ShouldApply { get; set; } } public class NamingStatistics { public int TotalIdentifiers { get; set; } public int ConventionViolations { get; set; } public int MeaningfulnessIssues { get; set; } public int AbbreviationIssues { get; set; } public Dictionary SeverityBreakdown { get; set; } = new Dictionary(); public Dictionary TypeBreakdown { get; set; } = new Dictionary(); public double QualityScore { get; set; } } }