MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Analysis/BehaviorAnalysisPlugin.cs

1791 lines
61 KiB
C#
Executable File

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.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace MarketAlly.AIPlugin.Analysis.Plugins
{
[AIPlugin("BehaviorAnalysis", "Analyzes code behavior against specifications and detects semantic drift")]
public class BehaviorAnalysisPlugin : IAIPlugin
{
[AIParameter("Full path to the file or directory to analyze", required: true)]
public string Path { get; set; } = string.Empty;
[AIParameter("Path to specification file or documentation", required: false)]
public string SpecificationPath { get; set; } = string.Empty;
[AIParameter("Generate natural language summaries of code behavior", required: false)]
public bool GenerateSummaries { get; set; } = true;
[AIParameter("Compare behavior against previous versions", required: false)]
public bool CompareVersions { get; set; } = false;
[AIParameter("Detect breaking changes in public APIs", required: false)]
public bool DetectBreakingChanges { get; set; } = true;
[AIParameter("Validate intent alignment with specifications", required: false)]
public bool ValidateIntent { get; set; } = true;
[AIParameter("Generate behavior test suggestions", required: false)]
public bool SuggestTests { get; set; } = true;
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
{
["path"] = typeof(string),
["specificationPath"] = typeof(string),
["generateSummaries"] = typeof(bool),
["compareVersions"] = typeof(bool),
["detectBreakingChanges"] = typeof(bool),
["validateIntent"] = typeof(bool),
["suggestTests"] = typeof(bool)
};
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
{
try
{
// Extract parameters
string path = parameters["path"]?.ToString() ?? string.Empty;
string? specificationPath = parameters.TryGetValue("specificationPath", out var specPath)
? specPath?.ToString()
: null;
bool generateSummaries = GetBoolParameter(parameters, "generateSummaries", true);
bool compareVersions = GetBoolParameter(parameters, "compareVersions", false);
bool detectBreakingChanges = GetBoolParameter(parameters, "detectBreakingChanges", true);
bool validateIntent = GetBoolParameter(parameters, "validateIntent", true);
bool suggestTests = GetBoolParameter(parameters, "suggestTests", true);
// Validate path
if (!File.Exists(path) && !Directory.Exists(path))
{
return new AIPluginResult(
new FileNotFoundException($"Path not found: {path}"),
"Path not found"
);
}
// Initialize behavior analysis
var analysis = new BehaviorAnalysis
{
AnalysisPath = path,
SpecificationPath = specificationPath ?? string.Empty,
AnalysisDate = DateTime.UtcNow,
BehaviorSummaries = new List<BehaviorSummary>(),
SpecificationAlignments = new List<SpecificationAlignment>(),
SemanticDrifts = new List<SemanticDrift>(),
BreakingChanges = new List<BreakingChange>(),
TestSuggestions = new List<BehaviorTestSuggestion>(),
IntentValidations = new List<IntentValidation>()
};
// Discover and analyze code files
await DiscoverAndAnalyzeCode(path, analysis);
// Load and analyze specifications
if (!string.IsNullOrEmpty(specificationPath) && File.Exists(specificationPath))
{
await AnalyzeSpecifications(specificationPath, analysis);
}
// Generate behavior summaries
if (generateSummaries)
{
await GenerateBehaviorSummaries(analysis);
}
// Compare with previous versions
if (compareVersions)
{
await CompareWithPreviousVersions(analysis);
}
// Detect breaking changes
if (detectBreakingChanges)
{
await DetectBreakingChangesMethod(analysis);
}
// Validate intent alignment
if (validateIntent)
{
await ValidateIntentAlignment(analysis);
}
// Generate test suggestions
if (suggestTests)
{
await GenerateBehaviorTestSuggestions(analysis);
}
// Calculate behavior health score
var behaviorScore = CalculateBehaviorScore(analysis);
var result = new
{
Path = path,
SpecificationPath = specificationPath,
AnalysisDate = analysis.AnalysisDate,
BehaviorScore = behaviorScore,
CodeStructure = new
{
TotalClasses = analysis.AnalyzedClasses.Count,
TotalMethods = analysis.AnalyzedMethods.Count,
PublicAPIs = analysis.AnalyzedMethods.Count(m => m.IsPublic),
BusinessLogicMethods = analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic)
},
BehaviorSummary = generateSummaries && analysis.BehaviorSummaries.Any() ?
analysis.BehaviorSummaries.First().Summary :
"Behavior summary generation was disabled or no summaries generated",
SpecificationAlignment = validateIntent && !string.IsNullOrEmpty(specificationPath) ?
analysis.SpecificationAlignments.Select(s => new
{
s.Component,
s.SpecificationRequirement,
s.ActualBehavior,
s.AlignmentLevel,
s.Discrepancies,
s.Recommendations
}).ToList() : null,
SemanticDrift = compareVersions ? analysis.SemanticDrifts.Select(d => new
{
d.Component,
d.DriftType,
d.Description,
d.Severity,
d.Impact,
d.Recommendation,
d.DetectedAt
}).ToList() : null,
BreakingChanges = detectBreakingChanges ? analysis.BreakingChanges.Select(b => new
{
b.ChangeType,
b.Component,
b.Description,
b.Impact,
b.Severity,
b.MitigationStrategy,
b.AffectedAPIs
}).ToList() : null,
TestSuggestions = suggestTests ? analysis.TestSuggestions.Select(t => new
{
t.TestType,
t.TargetComponent,
t.BehaviorToTest,
t.TestScenario,
t.Priority,
t.Rationale,
t.Implementation
}).OrderByDescending(t => t.Priority).ToList() : null,
IntentValidation = validateIntent ? new
{
OverallAlignment = analysis.IntentValidations.Any() ?
analysis.IntentValidations.Average(i => i.AlignmentScore) : 0,
ValidatedComponents = analysis.IntentValidations.Count,
HighAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore >= 80),
LowAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore < 60),
KeyFindings = analysis.IntentValidations
.Where(i => i.AlignmentScore < 70)
.Select(i => $"{i.Component}: {i.Finding}")
.Take(5)
.ToList()
} : null,
Summary = new
{
OverallBehaviorHealth = GetBehaviorHealth(behaviorScore),
CriticalIssues = analysis.BreakingChanges.Count(b => b.Severity == "High") +
analysis.SemanticDrifts.Count(d => d.Severity == "High"),
SpecificationCompliance = analysis.SpecificationAlignments.Any() ?
$"{analysis.SpecificationAlignments.Count(s => s.AlignmentLevel >= 80)}/{analysis.SpecificationAlignments.Count} components aligned" :
"No specifications provided",
TopRecommendations = GetTopBehaviorRecommendations(analysis),
BehaviorComplexity = GetBehaviorComplexity(analysis)
}
};
return new AIPluginResult(result,
$"Behavior analysis completed. Score: {behaviorScore}/100. " +
$"Analyzed {analysis.AnalyzedMethods.Count} methods across {analysis.AnalyzedClasses.Count} classes.");
}
catch (Exception ex)
{
return new AIPluginResult(ex, "Failed to analyze code behavior");
}
}
private Task DetectBreakingChangesMethod(BehaviorAnalysis analysis)
{
foreach (var method in analysis.AnalyzedMethods.Where(m => m.IsPublic))
{
var breakingChanges = AnalyzeMethodForBreakingChanges(method);
analysis.BreakingChanges.AddRange(breakingChanges);
}
foreach (var classInfo in analysis.AnalyzedClasses.Where(c => c.IsPublic))
{
var breakingChanges = AnalyzeClassForBreakingChanges(classInfo);
analysis.BreakingChanges.AddRange(breakingChanges);
}
return Task.CompletedTask;
}
private async Task DiscoverAndAnalyzeCode(string path, BehaviorAnalysis analysis)
{
var files = GetFilesToAnalyze(path);
foreach (var filePath in files)
{
var sourceCode = await File.ReadAllTextAsync(filePath);
var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode, path: filePath);
var root = await syntaxTree.GetRootAsync();
// Analyze classes
var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var cls in classes)
{
var classInfo = AnalyzeClassBehavior(cls, filePath);
analysis.AnalyzedClasses.Add(classInfo);
}
// Analyze methods
var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var method in methods)
{
var methodInfo = AnalyzeMethodBehavior(method, filePath);
analysis.AnalyzedMethods.Add(methodInfo);
}
}
}
private ClassBehaviorInfo AnalyzeClassBehavior(ClassDeclarationSyntax cls, string filePath)
{
var className = cls.Identifier.ValueText;
var namespaceName = GetNamespace(cls);
return new ClassBehaviorInfo
{
Name = className,
FullName = $"{namespaceName}.{className}",
Namespace = namespaceName,
FilePath = filePath,
IsPublic = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)),
IsAbstract = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword)),
BaseTypes = cls.BaseList?.Types.Select(t => t.Type.ToString()).ToList() ?? new List<string>(),
Responsibilities = ExtractClassResponsibilities(cls),
DesignPatterns = DetectDesignPatterns(cls),
BehaviorCategory = DetermineBehaviorCategory(cls),
ComplexityIndicators = AnalyzeClassComplexity(cls)
};
}
private MethodBehaviorInfo AnalyzeMethodBehavior(MethodDeclarationSyntax method, string filePath)
{
var className = GetContainingClassName(method);
var methodName = method.Identifier.ValueText;
return new MethodBehaviorInfo
{
Name = methodName,
ClassName = className,
FilePath = filePath,
LineNumber = method.GetLocation().GetLineSpan().StartLinePosition.Line + 1,
IsPublic = method.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)),
IsAsync = method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)),
ReturnType = method.ReturnType.ToString(),
Parameters = ExtractParameterInfo(method),
BehaviorType = DetermineBehaviorType(method),
SideEffects = AnalyzeSideEffects(method),
Preconditions = ExtractPreconditions(method),
Postconditions = ExtractPostconditions(method),
BusinessRules = ExtractBusinessRules(method),
HasBusinessLogic = HasBusinessLogic(method),
DataFlow = AnalyzeDataFlow(method),
ControlFlow = AnalyzeControlFlow(method)
};
}
private async Task AnalyzeSpecifications(string specificationPath, BehaviorAnalysis analysis)
{
var specContent = await File.ReadAllTextAsync(specificationPath);
var requirements = ParseSpecificationRequirements(specContent);
analysis.SpecificationRequirements = requirements;
}
private Task GenerateBehaviorSummaries(BehaviorAnalysis analysis)
{
// Generate overall system behavior summary
var systemSummary = new BehaviorSummary
{
Component = "System",
BehaviorType = "Overall",
Summary = GenerateSystemBehaviorSummary(analysis),
KeyBehaviors = ExtractKeySystemBehaviors(analysis),
ComplexityLevel = GetComplexityLevel(CalculateSystemComplexity(analysis)),
BusinessValue = AssessBusinessValue(analysis)
};
analysis.BehaviorSummaries.Add(systemSummary);
// Generate class-level summaries for key classes
var keyClasses = analysis.AnalyzedClasses
.Where(c => c.IsPublic || c.BehaviorCategory == "BusinessLogic")
.Take(10);
foreach (var classInfo in keyClasses)
{
var classSummary = new BehaviorSummary
{
Component = classInfo.Name,
BehaviorType = "Class",
Summary = GenerateClassBehaviorSummary(classInfo, analysis),
KeyBehaviors = ExtractClassKeyBehaviors(classInfo, analysis),
ComplexityLevel = GetComplexityLevel(classInfo.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0)),
BusinessValue = AssessClassBusinessValue(classInfo)
};
analysis.BehaviorSummaries.Add(classSummary);
}
return Task.CompletedTask;
}
private async Task CompareWithPreviousVersions(BehaviorAnalysis analysis)
{
// Load previous analysis if available
var previousAnalysisPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(analysis.AnalysisPath) ?? string.Empty, ".behavior-history.json");
if (File.Exists(previousAnalysisPath))
{
try
{
var previousData = await File.ReadAllTextAsync(previousAnalysisPath);
var previousAnalysis = JsonSerializer.Deserialize<BehaviorSnapshot>(previousData);
if (previousAnalysis != null)
{
DetectSemanticDrift(analysis, previousAnalysis);
}
}
catch
{
// Ignore errors loading previous analysis
}
}
// Save current analysis for future comparison
await SaveBehaviorSnapshot(analysis, previousAnalysisPath);
}
private Task ValidateIntentAlignment(BehaviorAnalysis analysis)
{
foreach (var method in analysis.AnalyzedMethods)
{
var validation = ValidateMethodIntent(method, analysis.SpecificationRequirements);
analysis.IntentValidations.Add(validation);
}
foreach (var classInfo in analysis.AnalyzedClasses)
{
var validation = ValidateClassIntent(classInfo, analysis.SpecificationRequirements);
analysis.IntentValidations.Add(validation);
}
return Task.CompletedTask;
}
private Task GenerateBehaviorTestSuggestions(BehaviorAnalysis analysis)
{
foreach (var method in analysis.AnalyzedMethods)
{
var suggestions = GenerateMethodTestSuggestions(method);
analysis.TestSuggestions.AddRange(suggestions);
}
// Generate integration test suggestions
var integrationSuggestions = GenerateIntegrationTestSuggestions(analysis);
analysis.TestSuggestions.AddRange(integrationSuggestions);
// Generate behavior-driven test suggestions
var bddSuggestions = GenerateBDDTestSuggestions(analysis);
analysis.TestSuggestions.AddRange(bddSuggestions);
return Task.CompletedTask;
}
// Helper methods for behavior analysis
private List<string> GetFilesToAnalyze(string path)
{
var files = new List<string>();
if (File.Exists(path) && path.EndsWith(".cs"))
{
files.Add(path);
}
else if (Directory.Exists(path))
{
files.AddRange(Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories)
.Where(f => !f.Contains("\\bin\\") && !f.Contains("\\obj\\") &&
!f.EndsWith(".Designer.cs") && !f.EndsWith(".g.cs")));
}
return files;
}
private string GetNamespace(SyntaxNode node)
{
var namespaceDecl = node.Ancestors().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();
return namespaceDecl?.Name.ToString() ?? "Global";
}
private string GetContainingClassName(SyntaxNode node)
{
var classDeclaration = node.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault();
return classDeclaration?.Identifier.ValueText ?? "Unknown";
}
private List<string> ExtractClassResponsibilities(ClassDeclarationSyntax cls)
{
var responsibilities = new List<string>();
// Analyze method names to infer responsibilities
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
var methodGroups = methods
.GroupBy(m => GetMethodCategory(m.Identifier.ValueText))
.Where(g => g.Key != "Unknown");
foreach (var group in methodGroups)
{
responsibilities.Add($"{group.Key} operations ({group.Count()} methods)");
}
// Analyze properties for data responsibilities
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
if (properties.Any())
{
responsibilities.Add($"Data management ({properties.Count()} properties)");
}
return responsibilities;
}
private List<string> DetectDesignPatterns(ClassDeclarationSyntax cls)
{
var patterns = new List<string>();
var className = cls.Identifier.ValueText;
// Pattern detection based on naming and structure
if (className.EndsWith("Factory")) patterns.Add("Factory Pattern");
if (className.EndsWith("Builder")) patterns.Add("Builder Pattern");
if (className.EndsWith("Observer")) patterns.Add("Observer Pattern");
if (className.EndsWith("Strategy")) patterns.Add("Strategy Pattern");
if (className.EndsWith("Command")) patterns.Add("Command Pattern");
if (className.EndsWith("Facade")) patterns.Add("Facade Pattern");
if (className.EndsWith("Adapter")) patterns.Add("Adapter Pattern");
if (className.EndsWith("Repository")) patterns.Add("Repository Pattern");
if (className.EndsWith("Service")) patterns.Add("Service Pattern");
// Singleton pattern detection
var constructors = cls.DescendantNodes().OfType<ConstructorDeclarationSyntax>();
if (constructors.Any(c => c.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))))
{
var fields = cls.DescendantNodes().OfType<FieldDeclarationSyntax>();
if (fields.Any(f => f.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))))
{
patterns.Add("Singleton Pattern");
}
}
return patterns;
}
private string DetermineBehaviorCategory(ClassDeclarationSyntax cls)
{
var className = cls.Identifier.ValueText.ToLowerInvariant();
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
if (className.Contains("controller")) return "Presentation";
if (className.Contains("service")) return "BusinessLogic";
if (className.Contains("repository") || className.Contains("dao")) return "DataAccess";
if (className.Contains("model") || className.Contains("entity")) return "Domain";
if (className.Contains("dto") || className.Contains("request") || className.Contains("response")) return "DataTransfer";
if (className.Contains("helper") || className.Contains("util")) return "Utility";
// Analyze method patterns
var businessMethods = methods.Count(m => HasBusinessLogic(m));
var dataMethods = methods.Count(m => AccessesData(m));
if (businessMethods > methods.Count() * 0.6) return "BusinessLogic";
if (dataMethods > methods.Count() * 0.5) return "DataAccess";
return "General";
}
private Dictionary<string, int> AnalyzeClassComplexity(ClassDeclarationSyntax cls)
{
var metrics = new Dictionary<string, int>();
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
metrics["MethodCount"] = methods.Count();
metrics["PropertyCount"] = properties.Count();
metrics["CyclomaticComplexity"] = methods.Sum(m => CalculateMethodComplexity(m));
metrics["Responsibilities"] = ExtractClassResponsibilities(cls).Count;
metrics["Dependencies"] = ExtractClassDependencies(cls).Count;
return metrics;
}
private List<ParameterInfo> ExtractParameterInfo(MethodDeclarationSyntax method)
{
return method.ParameterList.Parameters.Select(p => new ParameterInfo
{
Name = p.Identifier.ValueText,
Type = p.Type?.ToString() ?? "unknown",
HasDefaultValue = p.Default != null,
IsOptional = p.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))
}).ToList();
}
private string DetermineBehaviorType(MethodDeclarationSyntax method)
{
var methodName = method.Identifier.ValueText.ToLowerInvariant();
var returnType = method.ReturnType.ToString().ToLowerInvariant();
if (methodName.StartsWith("get") || methodName.StartsWith("retrieve")) return "Query";
if (methodName.StartsWith("set") || methodName.StartsWith("update") || methodName.StartsWith("save")) return "Command";
if (methodName.StartsWith("create") || methodName.StartsWith("add")) return "Creation";
if (methodName.StartsWith("delete") || methodName.StartsWith("remove")) return "Deletion";
if (methodName.StartsWith("validate") || methodName.StartsWith("check")) return "Validation";
if (methodName.StartsWith("calculate") || methodName.StartsWith("compute")) return "Computation";
if (methodName.StartsWith("process") || methodName.StartsWith("handle")) return "Processing";
if (returnType == "bool" || methodName.StartsWith("is") || methodName.StartsWith("has")) return "Predicate";
return "General";
}
private List<string> AnalyzeSideEffects(MethodDeclarationSyntax method)
{
var sideEffects = new List<string>();
var methodBody = method.Body?.ToString() ?? method.ExpressionBody?.ToString() ?? "";
if (methodBody.Contains("Console.Write") || methodBody.Contains("Console.Out"))
sideEffects.Add("Console Output");
if (methodBody.Contains("File.") || methodBody.Contains("Directory."))
sideEffects.Add("File System Access");
if (methodBody.Contains("HttpClient") || methodBody.Contains("WebRequest"))
sideEffects.Add("Network Communication");
if (methodBody.Contains("Database") || methodBody.Contains("Connection") || methodBody.Contains("Command"))
sideEffects.Add("Database Modification");
// Check for field modifications
var assignments = method.DescendantNodes().OfType<AssignmentExpressionSyntax>();
if (assignments.Any(a => !IsLocalVariable(a.Left)))
sideEffects.Add("State Modification");
if (method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)))
sideEffects.Add("Asynchronous Operation");
return sideEffects;
}
private List<string> ExtractPreconditions(MethodDeclarationSyntax method)
{
var preconditions = new List<string>();
// Look for parameter validation
var throwStatements = method.DescendantNodes().OfType<ThrowStatementSyntax>();
foreach (var throwStmt in throwStatements)
{
var condition = ExtractConditionFromThrow(throwStmt);
if (!string.IsNullOrEmpty(condition))
{
preconditions.Add(condition);
}
}
// Look for guard clauses
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>().Take(3); // First few conditions are likely guards
foreach (var ifStmt in ifStatements)
{
if (IsGuardClause(ifStmt))
{
preconditions.Add($"Guard: {ifStmt.Condition}");
}
}
return preconditions;
}
private List<string> ExtractPostconditions(MethodDeclarationSyntax method)
{
var postconditions = new List<string>();
var returnType = method.ReturnType.ToString();
// Analyze return statements
var returnStatements = method.DescendantNodes().OfType<ReturnStatementSyntax>();
if (returnStatements.Any() && returnType != "void")
{
postconditions.Add($"Returns: {returnType}");
}
// Look for assertions or validation at method end
var lastStatements = GetLastStatements(method, 3);
foreach (var stmt in lastStatements)
{
if (IsPostconditionCheck(stmt))
{
postconditions.Add($"Ensures: {stmt}");
}
}
return postconditions;
}
private List<string> ExtractBusinessRules(MethodDeclarationSyntax method)
{
var businessRules = new List<string>();
// Look for business logic patterns
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>();
foreach (var ifStmt in ifStatements)
{
if (IsBusinessRule(ifStmt))
{
businessRules.Add($"Rule: {SimplifyCondition(ifStmt.Condition.ToString())}");
}
}
// Look for switch statements (often business rules)
var switchStatements = method.DescendantNodes().OfType<SwitchStatementSyntax>();
foreach (var switchStmt in switchStatements)
{
businessRules.Add($"Business Logic Switch: {switchStmt.Expression}");
}
return businessRules;
}
private bool HasBusinessLogic(MethodDeclarationSyntax method)
{
var methodName = method.Identifier.ValueText.ToLowerInvariant();
var businessKeywords = new[] { "calculate", "process", "validate", "execute", "handle", "manage", "apply", "determine" };
if (businessKeywords.Any(keyword => methodName.Contains(keyword)))
return true;
// Check for complex logic
var complexity = CalculateMethodComplexity(method);
return complexity > 5;
}
private List<string> AnalyzeDataFlow(MethodDeclarationSyntax method)
{
var dataFlow = new List<string>();
var parameters = method.ParameterList.Parameters;
var returnType = method.ReturnType.ToString();
if (parameters.Any())
{
dataFlow.Add($"Input: {string.Join(", ", parameters.Select(p => p.Type))}");
}
if (returnType != "void")
{
dataFlow.Add($"Output: {returnType}");
}
// Analyze intermediate data transformations
var variableDeclarations = method.DescendantNodes().OfType<VariableDeclarationSyntax>();
var transformations = variableDeclarations.Count();
if (transformations > 0)
{
dataFlow.Add($"Transformations: {transformations} intermediate variables");
}
return dataFlow;
}
private List<string> AnalyzeControlFlow(MethodDeclarationSyntax method)
{
var controlFlow = new List<string>();
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>().Count();
var loops = method.DescendantNodes().OfType<ForStatementSyntax>().Count() +
method.DescendantNodes().OfType<WhileStatementSyntax>().Count() +
method.DescendantNodes().OfType<ForEachStatementSyntax>().Count();
var switches = method.DescendantNodes().OfType<SwitchStatementSyntax>().Count();
var tryCatch = method.DescendantNodes().OfType<TryStatementSyntax>().Count();
if (ifStatements > 0) controlFlow.Add($"Conditional: {ifStatements} if statements");
if (loops > 0) controlFlow.Add($"Iterative: {loops} loops");
if (switches > 0) controlFlow.Add($"Selection: {switches} switch statements");
if (tryCatch > 0) controlFlow.Add($"Exception Handling: {tryCatch} try-catch blocks");
var complexity = CalculateMethodComplexity(method);
controlFlow.Add($"Cyclomatic Complexity: {complexity}");
return controlFlow;
}
private List<SpecificationRequirement> ParseSpecificationRequirements(string specContent)
{
var requirements = new List<SpecificationRequirement>();
// Simple parsing for common specification formats
var lines = specContent.Split('\n', StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var trimmedLine = line.Trim();
// Look for requirement patterns
if (trimmedLine.StartsWith("REQ-") || trimmedLine.StartsWith("REQUIREMENT") ||
trimmedLine.Contains("SHALL") || trimmedLine.Contains("MUST"))
{
requirements.Add(new SpecificationRequirement
{
Id = ExtractRequirementId(trimmedLine),
Description = trimmedLine,
Priority = DetermineRequirementPriority(trimmedLine),
Category = DetermineRequirementCategory(trimmedLine)
});
}
}
return requirements;
}
private string GenerateSystemBehaviorSummary(BehaviorAnalysis analysis)
{
var summary = new List<string>();
summary.Add($"System contains {analysis.AnalyzedClasses.Count} classes and {analysis.AnalyzedMethods.Count} methods.");
var publicMethods = analysis.AnalyzedMethods.Count(m => m.IsPublic);
summary.Add($"Exposes {publicMethods} public methods as API surface.");
var behaviorCategories = analysis.AnalyzedClasses
.GroupBy(c => c.BehaviorCategory)
.ToDictionary(g => g.Key, g => g.Count());
summary.Add("Behavior distribution:");
foreach (var category in behaviorCategories)
{
summary.Add($" - {category.Key}: {category.Value} classes");
}
var businessLogicMethods = analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic);
summary.Add($"Contains {businessLogicMethods} methods with business logic.");
return string.Join(" ", summary);
}
private List<string> ExtractKeySystemBehaviors(BehaviorAnalysis analysis)
{
var keyBehaviors = new List<string>();
// Extract most common behavior types
var behaviorTypes = analysis.AnalyzedMethods
.GroupBy(m => m.BehaviorType)
.OrderByDescending(g => g.Count())
.Take(5);
foreach (var behavior in behaviorTypes)
{
keyBehaviors.Add($"{behavior.Key} operations ({behavior.Count()} methods)");
}
// Extract key side effects
var sideEffects = analysis.AnalyzedMethods
.SelectMany(m => m.SideEffects)
.GroupBy(s => s)
.OrderByDescending(g => g.Count())
.Take(3);
foreach (var effect in sideEffects)
{
keyBehaviors.Add($"{effect.Key} ({effect.Count()} occurrences)");
}
return keyBehaviors;
}
private int CalculateSystemComplexity(BehaviorAnalysis analysis)
{
var totalComplexity = analysis.AnalyzedClasses.Sum(c =>
c.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0));
var averageComplexity = analysis.AnalyzedClasses.Count > 0 ?
totalComplexity / analysis.AnalyzedClasses.Count : 0;
return averageComplexity;
}
private string AssessBusinessValue(BehaviorAnalysis analysis)
{
var businessLogicRatio = analysis.AnalyzedMethods.Count > 0 ?
(double)analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic) / analysis.AnalyzedMethods.Count : 0;
if (businessLogicRatio > 0.6) return "High";
if (businessLogicRatio > 0.3) return "Medium";
return "Low";
}
private string GenerateClassBehaviorSummary(ClassBehaviorInfo classInfo, BehaviorAnalysis analysis)
{
var summary = new List<string>();
summary.Add($"{classInfo.Name} is a {classInfo.BehaviorCategory} class");
if (classInfo.Responsibilities.Any())
{
summary.Add($"with responsibilities: {string.Join(", ", classInfo.Responsibilities)}");
}
if (classInfo.DesignPatterns.Any())
{
summary.Add($"Implements: {string.Join(", ", classInfo.DesignPatterns)}");
}
var methodCount = analysis.AnalyzedMethods.Count(m => m.ClassName == classInfo.Name);
summary.Add($"Contains {methodCount} methods");
return string.Join(". ", summary);
}
private List<string> ExtractClassKeyBehaviors(ClassBehaviorInfo classInfo, BehaviorAnalysis analysis)
{
var keyBehaviors = new List<string>();
var classMethods = analysis.AnalyzedMethods.Where(m => m.ClassName == classInfo.Name);
// Group methods by behavior type
var behaviorGroups = classMethods
.GroupBy(m => m.BehaviorType)
.OrderByDescending(g => g.Count());
foreach (var group in behaviorGroups.Take(3))
{
keyBehaviors.Add($"{group.Key} ({group.Count()} methods)");
}
// Add significant side effects
var sideEffects = classMethods
.SelectMany(m => m.SideEffects)
.GroupBy(s => s)
.OrderByDescending(g => g.Count())
.Take(2);
foreach (var effect in sideEffects)
{
keyBehaviors.Add($"{effect.Key}");
}
return keyBehaviors;
}
private void DetectSemanticDrift(BehaviorAnalysis current, BehaviorSnapshot previous)
{
// Compare method signatures and behaviors
foreach (var currentMethod in current.AnalyzedMethods)
{
var previousMethod = previous.Methods.FirstOrDefault(m =>
m.Name == currentMethod.Name && m.ClassName == currentMethod.ClassName);
if (previousMethod != null)
{
var drifts = CompareMethodBehavior(currentMethod, previousMethod);
current.SemanticDrifts.AddRange(drifts);
}
}
// Compare class structures
foreach (var currentClass in current.AnalyzedClasses)
{
var previousClass = previous.Classes.FirstOrDefault(c => c.Name == currentClass.Name);
if (previousClass != null)
{
var drifts = CompareClassBehavior(currentClass, previousClass);
current.SemanticDrifts.AddRange(drifts);
}
}
}
private List<SemanticDrift> CompareMethodBehavior(MethodBehaviorInfo current, MethodSnapshot previous)
{
var drifts = new List<SemanticDrift>();
// Check behavior type changes
if (current.BehaviorType != previous.BehaviorType)
{
drifts.Add(new SemanticDrift
{
Component = $"{current.ClassName}.{current.Name}",
DriftType = "Behavior Type Change",
Description = $"Behavior changed from {previous.BehaviorType} to {current.BehaviorType}",
Severity = "Medium",
Impact = "Method semantics may have changed",
Recommendation = "Review method implementation and update documentation",
DetectedAt = DateTime.UtcNow
});
}
// Check side effects changes
var newSideEffects = current.SideEffects.Except(previous.SideEffects).ToList();
var removedSideEffects = previous.SideEffects.Except(current.SideEffects).ToList();
if (newSideEffects.Any())
{
drifts.Add(new SemanticDrift
{
Component = $"{current.ClassName}.{current.Name}",
DriftType = "New Side Effects",
Description = $"Added side effects: {string.Join(", ", newSideEffects)}",
Severity = "High",
Impact = "Method now has additional side effects",
Recommendation = "Ensure callers handle new side effects appropriately",
DetectedAt = DateTime.UtcNow
});
}
if (removedSideEffects.Any())
{
drifts.Add(new SemanticDrift
{
Component = $"{current.ClassName}.{current.Name}",
DriftType = "Removed Side Effects",
Description = $"Removed side effects: {string.Join(", ", removedSideEffects)}",
Severity = "Medium",
Impact = "Method no longer produces certain side effects",
Recommendation = "Verify that removed side effects are not needed",
DetectedAt = DateTime.UtcNow
});
}
return drifts;
}
private List<SemanticDrift> CompareClassBehavior(ClassBehaviorInfo current, ClassSnapshot previous)
{
var drifts = new List<SemanticDrift>();
// Check responsibility changes
var newResponsibilities = current.Responsibilities.Except(previous.Responsibilities).ToList();
var removedResponsibilities = previous.Responsibilities.Except(current.Responsibilities).ToList();
if (newResponsibilities.Any())
{
drifts.Add(new SemanticDrift
{
Component = current.Name,
DriftType = "New Responsibilities",
Description = $"Added responsibilities: {string.Join(", ", newResponsibilities)}",
Severity = "Medium",
Impact = "Class scope has expanded",
Recommendation = "Consider if class is becoming too complex",
DetectedAt = DateTime.UtcNow
});
}
return drifts;
}
private async Task SaveBehaviorSnapshot(BehaviorAnalysis analysis, string snapshotPath)
{
var snapshot = new BehaviorSnapshot
{
AnalysisDate = analysis.AnalysisDate,
Classes = analysis.AnalyzedClasses.Select(c => new ClassSnapshot
{
Name = c.Name,
BehaviorCategory = c.BehaviorCategory,
Responsibilities = c.Responsibilities,
DesignPatterns = c.DesignPatterns
}).ToList(),
Methods = analysis.AnalyzedMethods.Select(m => new MethodSnapshot
{
Name = m.Name,
ClassName = m.ClassName,
BehaviorType = m.BehaviorType,
SideEffects = m.SideEffects,
HasBusinessLogic = m.HasBusinessLogic
}).ToList()
};
try
{
var json = JsonSerializer.Serialize(snapshot, new JsonSerializerOptions { WriteIndented = true });
await File.WriteAllTextAsync(snapshotPath, json);
}
catch
{
// Ignore save errors
}
}
private List<BreakingChange> AnalyzeMethodForBreakingChanges(MethodBehaviorInfo method)
{
var breakingChanges = new List<BreakingChange>();
// Check for potential breaking changes based on method characteristics
if (method.SideEffects.Contains("Database Modification"))
{
breakingChanges.Add(new BreakingChange
{
ChangeType = "Data Modification",
Component = $"{method.ClassName}.{method.Name}",
Description = "Method modifies database state",
Impact = "Callers may experience data consistency issues",
Severity = "Medium",
MitigationStrategy = "Ensure proper transaction handling and rollback capabilities",
AffectedAPIs = new List<string> { $"{method.ClassName}.{method.Name}" }
});
}
if (method.SideEffects.Contains("Network Communication"))
{
breakingChanges.Add(new BreakingChange
{
ChangeType = "External Dependency",
Component = $"{method.ClassName}.{method.Name}",
Description = "Method depends on external network services",
Impact = "Method may fail due to network issues",
Severity = "Low",
MitigationStrategy = "Implement retry logic and graceful degradation",
AffectedAPIs = new List<string> { $"{method.ClassName}.{method.Name}" }
});
}
return breakingChanges;
}
private List<BreakingChange> AnalyzeClassForBreakingChanges(ClassBehaviorInfo classInfo)
{
var breakingChanges = new List<BreakingChange>();
// Check for inheritance changes
if (classInfo.BaseTypes.Any())
{
breakingChanges.Add(new BreakingChange
{
ChangeType = "Inheritance Structure",
Component = classInfo.Name,
Description = "Class has inheritance relationships that may constrain changes",
Impact = "Changes may affect derived classes",
Severity = "Medium",
MitigationStrategy = "Use interface segregation and dependency inversion",
AffectedAPIs = new List<string> { classInfo.Name }
});
}
return breakingChanges;
}
private IntentValidation ValidateMethodIntent(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
{
var validation = new IntentValidation
{
Component = $"{method.ClassName}.{method.Name}",
ComponentType = "Method",
ExpectedIntent = DetermineExpectedIntent(method),
ActualBehavior = DescribeActualBehavior(method),
AlignmentScore = CalculateAlignmentScore(method, requirements),
Finding = GenerateAlignmentFinding(method, requirements),
Recommendations = GenerateAlignmentRecommendations(method, requirements)
};
return validation;
}
private IntentValidation ValidateClassIntent(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
{
var validation = new IntentValidation
{
Component = classInfo.Name,
ComponentType = "Class",
ExpectedIntent = $"Implement {classInfo.BehaviorCategory} functionality",
ActualBehavior = string.Join(", ", classInfo.Responsibilities),
AlignmentScore = CalculateClassAlignmentScore(classInfo, requirements),
Finding = GenerateClassAlignmentFinding(classInfo, requirements),
Recommendations = GenerateClassAlignmentRecommendations(classInfo)
};
return validation;
}
private List<BehaviorTestSuggestion> GenerateMethodTestSuggestions(MethodBehaviorInfo method)
{
var suggestions = new List<BehaviorTestSuggestion>();
// Basic behavior tests
suggestions.Add(new BehaviorTestSuggestion
{
TestType = "Behavior Verification",
TargetComponent = $"{method.ClassName}.{method.Name}",
BehaviorToTest = $"Method exhibits {method.BehaviorType} behavior correctly",
TestScenario = $"Given valid inputs, when {method.Name} is called, then it should perform {method.BehaviorType} operation",
Priority = method.IsPublic ? 8 : 5,
Rationale = $"Verify core {method.BehaviorType} behavior",
Implementation = GenerateTestImplementation(method)
});
// Side effect tests
foreach (var sideEffect in method.SideEffects)
{
suggestions.Add(new BehaviorTestSuggestion
{
TestType = "Side Effect Verification",
TargetComponent = $"{method.ClassName}.{method.Name}",
BehaviorToTest = $"Method produces {sideEffect} side effect correctly",
TestScenario = $"When {method.Name} is called, then {sideEffect} should occur as expected",
Priority = GetSideEffectTestPriority(sideEffect),
Rationale = $"Ensure {sideEffect} side effect is properly controlled",
Implementation = GenerateSideEffectTestImplementation(method, sideEffect)
});
}
// Business rule tests
foreach (var rule in method.BusinessRules)
{
suggestions.Add(new BehaviorTestSuggestion
{
TestType = "Business Rule Verification",
TargetComponent = $"{method.ClassName}.{method.Name}",
BehaviorToTest = $"Business rule implementation: {rule}",
TestScenario = $"Given business scenario, when rule applies, then {rule} should be enforced",
Priority = 9,
Rationale = "Business rules are critical for domain correctness",
Implementation = GenerateBusinessRuleTestImplementation(method, rule)
});
}
return suggestions;
}
private List<BehaviorTestSuggestion> GenerateIntegrationTestSuggestions(BehaviorAnalysis analysis)
{
var suggestions = new List<BehaviorTestSuggestion>();
// Find classes that interact with external systems
var externallyConnectedClasses = analysis.AnalyzedClasses
.Where(c => analysis.AnalyzedMethods
.Where(m => m.ClassName == c.Name)
.Any(m => m.SideEffects.Contains("Database Modification") ||
m.SideEffects.Contains("Network Communication")))
.ToList();
foreach (var cls in externallyConnectedClasses)
{
suggestions.Add(new BehaviorTestSuggestion
{
TestType = "Integration Test",
TargetComponent = cls.Name,
BehaviorToTest = "End-to-end integration with external systems",
TestScenario = $"Given real external dependencies, when {cls.Name} operations are performed, then integration should work correctly",
Priority = 7,
Rationale = "Verify integration points work correctly in realistic scenarios",
Implementation = $"Create integration tests with test containers or mock services for {cls.Name}"
});
}
return suggestions;
}
private List<BehaviorTestSuggestion> GenerateBDDTestSuggestions(BehaviorAnalysis analysis)
{
var suggestions = new List<BehaviorTestSuggestion>();
var businessLogicClasses = analysis.AnalyzedClasses
.Where(c => c.BehaviorCategory == "BusinessLogic")
.ToList();
foreach (var cls in businessLogicClasses)
{
suggestions.Add(new BehaviorTestSuggestion
{
TestType = "Behavior-Driven Test",
TargetComponent = cls.Name,
BehaviorToTest = "Business behavior from user perspective",
TestScenario = $"Given business context, when user performs action, then {cls.Name} should deliver expected business outcome",
Priority = 8,
Rationale = "Ensure business behavior matches stakeholder expectations",
Implementation = $"Create Gherkin scenarios for {cls.Name} business operations"
});
}
return suggestions;
}
// Utility and helper methods
private int CalculateMethodComplexity(MethodDeclarationSyntax method)
{
var complexity = 1;
var descendants = method.DescendantNodes();
complexity += descendants.OfType<IfStatementSyntax>().Count();
complexity += descendants.OfType<WhileStatementSyntax>().Count();
complexity += descendants.OfType<ForStatementSyntax>().Count();
complexity += descendants.OfType<ForEachStatementSyntax>().Count();
complexity += descendants.OfType<SwitchStatementSyntax>().Count();
complexity += descendants.OfType<CatchClauseSyntax>().Count();
return complexity;
}
private string GetMethodCategory(string methodName)
{
var name = methodName.ToLowerInvariant();
if (name.StartsWith("get") || name.StartsWith("retrieve") || name.StartsWith("find")) return "Data Retrieval";
if (name.StartsWith("set") || name.StartsWith("update") || name.StartsWith("save")) return "Data Modification";
if (name.StartsWith("create") || name.StartsWith("add") || name.StartsWith("insert")) return "Data Creation";
if (name.StartsWith("delete") || name.StartsWith("remove")) return "Data Deletion";
if (name.StartsWith("validate") || name.StartsWith("check") || name.StartsWith("verify")) return "Validation";
if (name.StartsWith("calculate") || name.StartsWith("compute")) return "Calculation";
if (name.StartsWith("process") || name.StartsWith("handle") || name.StartsWith("execute")) return "Processing";
return "Unknown";
}
private bool AccessesData(MethodDeclarationSyntax method)
{
var methodBody = method.Body?.ToString() ?? method.ExpressionBody?.ToString() ?? "";
var dataKeywords = new[] { "database", "repository", "entity", "dbcontext", "connection", "command", "query" };
return dataKeywords.Any(keyword => methodBody.ToLowerInvariant().Contains(keyword));
}
private List<string> ExtractClassDependencies(ClassDeclarationSyntax cls)
{
var dependencies = new HashSet<string>();
// Extract from field types
var fields = cls.DescendantNodes().OfType<FieldDeclarationSyntax>();
foreach (var field in fields)
{
dependencies.Add(field.Declaration.Type.ToString());
}
// Extract from property types
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
foreach (var property in properties)
{
dependencies.Add(property.Type.ToString());
}
// Extract from constructor parameters
var constructors = cls.DescendantNodes().OfType<ConstructorDeclarationSyntax>();
foreach (var constructor in constructors)
{
foreach (var param in constructor.ParameterList.Parameters)
{
dependencies.Add(param.Type?.ToString() ?? "unknown");
}
}
return dependencies.Where(d => !string.IsNullOrEmpty(d) && !d.StartsWith("System.")).ToList();
}
private bool IsLocalVariable(ExpressionSyntax expression)
{
// Simple heuristic to determine if assignment target is a local variable
return expression is IdentifierNameSyntax identifier &&
char.IsLower(identifier.Identifier.ValueText[0]);
}
private string ExtractConditionFromThrow(ThrowStatementSyntax throwStmt)
{
var expression = throwStmt.Expression?.ToString() ?? "";
if (expression.Contains("ArgumentNullException")) return "Parameter must not be null";
if (expression.Contains("ArgumentException")) return "Parameter must be valid";
if (expression.Contains("InvalidOperationException")) return "Object must be in valid state";
return "Precondition check";
}
private bool IsGuardClause(IfStatementSyntax ifStmt)
{
// Check if if statement is likely a guard clause (early return/throw)
var statement = ifStmt.Statement;
return statement is ThrowStatementSyntax ||
(statement is BlockSyntax block &&
block.Statements.Count == 1 &&
(block.Statements[0] is ThrowStatementSyntax || block.Statements[0] is ReturnStatementSyntax));
}
private List<StatementSyntax> GetLastStatements(MethodDeclarationSyntax method, int count)
{
var statements = method.Body?.Statements ?? new SyntaxList<StatementSyntax>();
return statements.TakeLast(count).ToList();
}
private bool IsPostconditionCheck(StatementSyntax statement)
{
var statementText = statement.ToString().ToLowerInvariant();
return statementText.Contains("assert") || statementText.Contains("ensure") || statementText.Contains("contract");
}
private bool IsBusinessRule(IfStatementSyntax ifStmt)
{
var condition = ifStmt.Condition.ToString().ToLowerInvariant();
var businessIndicators = new[] { "status", "state", "type", "category", "amount", "count", "limit", "threshold" };
return businessIndicators.Any(indicator => condition.Contains(indicator));
}
private string SimplifyCondition(string condition)
{
// Simplify complex conditions for readability
if (condition.Length > 50)
{
return condition.Substring(0, 47) + "...";
}
return condition;
}
private string GetComplexityLevel(int complexity)
{
return complexity switch
{
<= 5 => "Low",
<= 10 => "Medium",
<= 20 => "High",
_ => "Very High"
};
}
private string AssessClassBusinessValue(ClassBehaviorInfo classInfo)
{
if (classInfo.BehaviorCategory == "BusinessLogic") return "High";
if (classInfo.BehaviorCategory == "Domain") return "High";
if (classInfo.BehaviorCategory == "Presentation") return "Medium";
if (classInfo.BehaviorCategory == "DataAccess") return "Medium";
return "Low";
}
private string ExtractRequirementId(string requirementText)
{
var match = Regex.Match(requirementText, @"REQ-\d+");
return match.Success ? match.Value : $"REQ-{Guid.NewGuid().ToString("N")[..8]}";
}
private string DetermineRequirementPriority(string requirementText)
{
var text = requirementText.ToLowerInvariant();
if (text.Contains("critical") || text.Contains("must")) return "High";
if (text.Contains("should") || text.Contains("important")) return "Medium";
return "Low";
}
private string DetermineRequirementCategory(string requirementText)
{
var text = requirementText.ToLowerInvariant();
if (text.Contains("performance") || text.Contains("speed")) return "Performance";
if (text.Contains("security") || text.Contains("authentication")) return "Security";
if (text.Contains("usability") || text.Contains("user")) return "Usability";
if (text.Contains("functional") || text.Contains("business")) return "Functional";
return "General";
}
private string DetermineExpectedIntent(MethodBehaviorInfo method)
{
return $"Perform {method.BehaviorType} operation with appropriate {string.Join(", ", method.SideEffects)} handling";
}
private string DescribeActualBehavior(MethodBehaviorInfo method)
{
var behaviors = new List<string> { $"{method.BehaviorType} operation" };
if (method.SideEffects.Any()) behaviors.Add($"Side effects: {string.Join(", ", method.SideEffects)}");
if (method.BusinessRules.Any()) behaviors.Add($"Business rules: {method.BusinessRules.Count}");
return string.Join("; ", behaviors);
}
private int CalculateAlignmentScore(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
{
// Simple scoring based on method characteristics
var score = 70; // Base score
if (method.HasBusinessLogic) score += 10;
if (method.Preconditions.Any()) score += 5;
if (method.Postconditions.Any()) score += 5;
if (method.BusinessRules.Any()) score += 10;
// Penalty for excessive side effects
if (method.SideEffects.Count > 3) score -= 10;
return Math.Max(0, Math.Min(100, score));
}
private string GenerateAlignmentFinding(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
{
if (method.HasBusinessLogic && method.BusinessRules.Any())
{
return "Method implements business logic with defined rules";
}
if (method.SideEffects.Count > 2)
{
return "Method has multiple side effects that may need review";
}
if (!method.Preconditions.Any() && method.Parameters.Any())
{
return "Method lacks input validation";
}
return "Method behavior appears aligned with expected patterns";
}
private List<string> GenerateAlignmentRecommendations(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
{
var recommendations = new List<string>();
if (!method.Preconditions.Any() && method.Parameters.Any())
{
recommendations.Add("Add input validation and precondition checks");
}
if (method.SideEffects.Count > 2)
{
recommendations.Add("Consider breaking method into smaller, more focused operations");
}
if (!method.BusinessRules.Any() && method.HasBusinessLogic)
{
recommendations.Add("Document business rules and make them more explicit");
}
return recommendations;
}
private int CalculateClassAlignmentScore(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
{
var score = 70; // Base score
if (classInfo.DesignPatterns.Any()) score += 15;
if (classInfo.Responsibilities.Count <= 3) score += 10; // Single Responsibility
if (classInfo.ComplexityIndicators["CyclomaticComplexity"] < 50) score += 5;
return Math.Max(0, Math.Min(100, score));
}
private string GenerateClassAlignmentFinding(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
{
if (classInfo.Responsibilities.Count > 5)
{
return "Class has many responsibilities and may violate Single Responsibility Principle";
}
if (classInfo.DesignPatterns.Any())
{
return $"Class implements recognized design patterns: {string.Join(", ", classInfo.DesignPatterns)}";
}
return "Class structure follows standard patterns";
}
private List<string> GenerateClassAlignmentRecommendations(ClassBehaviorInfo classInfo)
{
var recommendations = new List<string>();
if (classInfo.Responsibilities.Count > 5)
{
recommendations.Add("Consider splitting class to improve cohesion");
}
if (!classInfo.DesignPatterns.Any() && classInfo.ComplexityIndicators["MethodCount"] > 10)
{
recommendations.Add("Consider applying design patterns to improve structure");
}
return recommendations;
}
private string GenerateTestImplementation(MethodBehaviorInfo method)
{
return $"Create unit test for {method.Name} that verifies {method.BehaviorType} behavior with various input scenarios";
}
private int GetSideEffectTestPriority(string sideEffect)
{
return sideEffect switch
{
"Database Modification" => 9,
"Network Communication" => 8,
"File System Access" => 7,
"State Modification" => 6,
_ => 5
};
}
private string GenerateSideEffectTestImplementation(MethodBehaviorInfo method, string sideEffect)
{
return $"Create test that verifies {sideEffect} occurs correctly when {method.Name} is called";
}
private string GenerateBusinessRuleTestImplementation(MethodBehaviorInfo method, string rule)
{
return $"Create test scenarios that validate business rule: {rule}";
}
private int CalculateBehaviorScore(BehaviorAnalysis analysis)
{
var score = 100;
// Deduct for complexity issues
var avgComplexity = CalculateSystemComplexity(analysis);
if (avgComplexity > 20) score -= 20;
else if (avgComplexity > 10) score -= 10;
// Deduct for breaking changes
var criticalBreakingChanges = analysis.BreakingChanges.Count(b => b.Severity == "High");
score -= criticalBreakingChanges * 15;
// Deduct for semantic drift
var criticalDrifts = analysis.SemanticDrifts.Count(d => d.Severity == "High");
score -= criticalDrifts * 10;
// Bonus for good alignment
var avgAlignment = analysis.IntentValidations.Any() ?
analysis.IntentValidations.Average(i => i.AlignmentScore) : 70;
if (avgAlignment > 80) score += 10;
return Math.Max(0, Math.Min(100, score));
}
private string GetBehaviorHealth(int score)
{
return score switch
{
>= 80 => "Excellent",
>= 60 => "Good",
>= 40 => "Fair",
>= 20 => "Poor",
_ => "Critical"
};
}
private string GetBehaviorComplexity(BehaviorAnalysis analysis)
{
var avgComplexity = CalculateSystemComplexity(analysis);
return avgComplexity switch
{
<= 5 => "Low",
<= 10 => "Moderate",
<= 20 => "High",
_ => "Very High"
};
}
private List<string> GetTopBehaviorRecommendations(BehaviorAnalysis analysis)
{
var recommendations = new List<string>();
var criticalBreaking = analysis.BreakingChanges.Count(b => b.Severity == "High");
if (criticalBreaking > 0)
{
recommendations.Add($"Address {criticalBreaking} critical breaking changes");
}
var criticalDrifts = analysis.SemanticDrifts.Count(d => d.Severity == "High");
if (criticalDrifts > 0)
{
recommendations.Add($"Review {criticalDrifts} critical semantic drifts");
}
var lowAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore < 60);
if (lowAlignmentComponents > 0)
{
recommendations.Add($"Improve alignment for {lowAlignmentComponents} components");
}
var highComplexityClasses = analysis.AnalyzedClasses.Count(c =>
c.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0) > 20);
if (highComplexityClasses > 0)
{
recommendations.Add($"Refactor {highComplexityClasses} high-complexity classes");
}
var highPriorityTests = analysis.TestSuggestions.Count(t => t.Priority >= 8);
if (highPriorityTests > 0)
{
recommendations.Add($"Implement {highPriorityTests} high-priority behavior tests");
}
if (!recommendations.Any())
{
recommendations.Add("Behavior analysis shows good alignment - continue maintaining standards");
}
return recommendations.Take(5).ToList();
}
private bool GetBoolParameter(IReadOnlyDictionary<string, object> parameters, string key, bool defaultValue)
{
return parameters.TryGetValue(key, out var value) ? Convert.ToBoolean(value) : defaultValue;
}
}
// Supporting data structures for behavior analysis
public class BehaviorAnalysis
{
public string AnalysisPath { get; set; } = string.Empty;
public string? SpecificationPath { get; set; }
public DateTime AnalysisDate { get; set; }
public List<ClassBehaviorInfo> AnalyzedClasses { get; set; } = new();
public List<MethodBehaviorInfo> AnalyzedMethods { get; set; } = new();
public List<SpecificationRequirement> SpecificationRequirements { get; set; } = new();
public List<BehaviorSummary> BehaviorSummaries { get; set; } = new();
public List<SpecificationAlignment> SpecificationAlignments { get; set; } = new();
public List<SemanticDrift> SemanticDrifts { get; set; } = new();
public List<BreakingChange> BreakingChanges { get; set; } = new();
public List<BehaviorTestSuggestion> TestSuggestions { get; set; } = new();
public List<IntentValidation> IntentValidations { get; set; } = new();
}
public class ClassBehaviorInfo
{
public string Name { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public string Namespace { get; set; } = string.Empty;
public string FilePath { get; set; } = string.Empty;
public bool IsPublic { get; set; }
public bool IsAbstract { get; set; }
public List<string> BaseTypes { get; set; } = new();
public List<string> Responsibilities { get; set; } = new();
public List<string> DesignPatterns { get; set; } = new();
public string BehaviorCategory { get; set; } = string.Empty;
public Dictionary<string, int> ComplexityIndicators { get; set; } = new();
}
public class MethodBehaviorInfo
{
public string Name { get; set; } = string.Empty;
public string ClassName { get; set; } = string.Empty;
public string FilePath { get; set; } = string.Empty;
public int LineNumber { get; set; }
public bool IsPublic { get; set; }
public bool IsAsync { get; set; }
public string ReturnType { get; set; } = string.Empty;
public List<ParameterInfo> Parameters { get; set; } = new();
public string BehaviorType { get; set; } = string.Empty;
public List<string> SideEffects { get; set; } = new();
public List<string> Preconditions { get; set; } = new();
public List<string> Postconditions { get; set; } = new();
public List<string> BusinessRules { get; set; } = new();
public bool HasBusinessLogic { get; set; }
public List<string> DataFlow { get; set; } = new();
public List<string> ControlFlow { get; set; } = new();
}
public class ParameterInfo
{
public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public bool HasDefaultValue { get; set; }
public bool IsOptional { get; set; }
}
public class SpecificationRequirement
{
public string Id { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Priority { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
}
public class BehaviorSummary
{
public string Component { get; set; } = string.Empty;
public string BehaviorType { get; set; } = string.Empty;
public string Summary { get; set; } = string.Empty;
public List<string> KeyBehaviors { get; set; } = new();
public string ComplexityLevel { get; set; } = string.Empty;
public string BusinessValue { get; set; } = string.Empty;
}
public class SpecificationAlignment
{
public string Component { get; set; } = string.Empty;
public string SpecificationRequirement { get; set; } = string.Empty;
public string ActualBehavior { get; set; } = string.Empty;
public int AlignmentLevel { get; set; }
public List<string> Discrepancies { get; set; } = new();
public List<string> Recommendations { get; set; } = new();
}
public class SemanticDrift
{
public string Component { get; set; } = string.Empty;
public string DriftType { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Severity { get; set; } = string.Empty;
public string Impact { get; set; } = string.Empty;
public string Recommendation { get; set; } = string.Empty;
public DateTime DetectedAt { get; set; }
}
public class BreakingChange
{
public string ChangeType { get; set; } = string.Empty;
public string Component { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Impact { get; set; } = string.Empty;
public string Severity { get; set; } = string.Empty;
public string MitigationStrategy { get; set; } = string.Empty;
public List<string> AffectedAPIs { get; set; } = new();
}
public class BehaviorTestSuggestion
{
public string TestType { get; set; } = string.Empty;
public string TargetComponent { get; set; } = string.Empty;
public string BehaviorToTest { get; set; } = string.Empty;
public string TestScenario { get; set; } = string.Empty;
public int Priority { get; set; }
public string Rationale { get; set; } = string.Empty;
public string Implementation { get; set; } = string.Empty;
}
public class IntentValidation
{
public string Component { get; set; } = string.Empty;
public string ComponentType { get; set; } = string.Empty;
public string ExpectedIntent { get; set; } = string.Empty;
public string ActualBehavior { get; set; } = string.Empty;
public int AlignmentScore { get; set; }
public string Finding { get; set; } = string.Empty;
public List<string> Recommendations { get; set; } = new();
}
public class BehaviorSnapshot
{
public DateTime AnalysisDate { get; set; }
public List<ClassSnapshot> Classes { get; set; } = new();
public List<MethodSnapshot> Methods { get; set; } = new();
}
public class ClassSnapshot
{
public string Name { get; set; } = string.Empty;
public string BehaviorCategory { get; set; } = string.Empty;
public List<string> Responsibilities { get; set; } = new();
public List<string> DesignPatterns { get; set; } = new();
}
public class MethodSnapshot
{
public string Name { get; set; } = string.Empty;
public string ClassName { get; set; } = string.Empty;
public string BehaviorType { get; set; } = string.Empty;
public List<string> SideEffects { get; set; } = new();
public bool HasBusinessLogic { get; set; }
}
}