using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Linq; using System.IO; using CodeMerger.ViewModels; using CodeMerger.Models; public class cCodeMerger { private const string CONTINUATION_MARKER = "// ... resto del código ..."; private class ClassNamespaceMapping { public Dictionary ClassToNamespace { get; } = new Dictionary(); public void AddMapping(string className, string namespaceName) { if (!ClassToNamespace.ContainsKey(className)) { ClassToNamespace[className] = namespaceName; } } public string GetNamespace(string className) { return ClassToNamespace.TryGetValue(className, out var ns) ? ns : null; } } private readonly ClassNamespaceMapping _classNamespaceMapping = new ClassNamespaceMapping(); public class MergeResult { public bool Success { get; set; } public string MergedCode { get; set; } public List Diagnostics { get; set; } = new List(); } public MergeResult MergeCode(string originalCode, string llmCode, string outputPath, LogViewModel logger) { var result = new MergeResult(); try { logger.AddLog("Starting code merge process..."); logger.AddLog("Parsing original code...", LogLevel.Debug); var originalTree = CSharpSyntaxTree.ParseText(originalCode); var originalRoot = originalTree.GetRoot() as CompilationUnitSyntax; logger.AddLog("Parsing LLM code...", LogLevel.Debug); var llmTree = CSharpSyntaxTree.ParseText(llmCode); var llmRoot = llmTree.GetRoot() as CompilationUnitSyntax; if (originalRoot == null || llmRoot == null) { logger.AddLog("Failed to parse syntax trees", LogLevel.Error); result.Success = false; result.Diagnostics.Add("Error parsing syntax trees"); return result; } logger.AddLog("Processing namespaces..."); var newRoot = ProcessNamespaces(originalRoot, llmRoot, logger); logger.AddLog("Formatting result..."); var formattedRoot = newRoot.NormalizeWhitespace(); logger.AddLog($"Writing output to: {outputPath}"); File.WriteAllText(outputPath, formattedRoot.ToFullString()); result.Success = true; result.MergedCode = formattedRoot.ToFullString(); logger.AddLog("Merge completed successfully!"); return result; } catch (Exception ex) { logger.AddLog($"Error during merge: {ex.Message}", LogLevel.Error); logger.AddLog(ex.StackTrace ?? "", LogLevel.Debug); result.Success = false; result.Diagnostics.Add($"Error during merge: {ex.Message}"); return result; } } private CompilationUnitSyntax ProcessNamespaces(CompilationUnitSyntax originalRoot, CompilationUnitSyntax llmRoot, LogViewModel logger) { logger.AddLog("Checking for top-level members in LLM code...", LogLevel.Debug); var topLevelMembers = GetTopLevelMembers(llmRoot).ToList(); if (topLevelMembers.Any()) { logger.AddLog("Found top-level members in LLM code, determining best namespace...", LogLevel.Debug); var targetNamespace = FindBestNamespaceForMembers(topLevelMembers, originalRoot, logger); // Create or update namespace with top-level members var existingNamespace = llmRoot.Members.OfType() .FirstOrDefault(ns => ns.Name.ToString() == targetNamespace); if (existingNamespace != null) { logger.AddLog($"Adding top-level members to existing namespace: {targetNamespace}", LogLevel.Debug); llmRoot = llmRoot.ReplaceNode(existingNamespace, existingNamespace.WithMembers( existingNamespace.Members.AddRange(topLevelMembers))); } else { logger.AddLog($"Creating new namespace {targetNamespace} for top-level members", LogLevel.Debug); var newNamespace = SyntaxFactory.NamespaceDeclaration( SyntaxFactory.ParseName(targetNamespace)) .WithMembers(SyntaxFactory.List(topLevelMembers)); llmRoot = llmRoot.WithMembers( SyntaxFactory.List( llmRoot.Members.Where(m => m is NamespaceDeclarationSyntax) .Concat(new[] { newNamespace }))); } } // Continue with existing namespace processing logger.AddLog("Analyzing LLM code structure:", LogLevel.Debug); var llmNamespaces = new Dictionary(); // Log and collect LLM namespaces foreach (var ns in llmRoot.Members.OfType()) { var nsName = ns.Name.ToString(); logger.AddLog($"Found LLM namespace: {nsName}", LogLevel.Debug); llmNamespaces[nsName] = ns; foreach (var cls in ns.Members.OfType()) { logger.AddLog($" Class in LLM: {cls.Identifier}", LogLevel.Debug); logger.AddLog(" Fields and Properties in LLM class:", LogLevel.Debug); // Log fields foreach (var field in cls.Members.OfType()) { foreach (var variable in field.Declaration.Variables) { logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug); } } // Log properties foreach (var prop in cls.Members.OfType()) { logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug); } foreach (var method in cls.Members.OfType()) { logger.AddLog($" Method: {method.Identifier}", LogLevel.Debug); } } } logger.AddLog("\nAnalyzing original code structure:", LogLevel.Debug); var namespacesToProcess = originalRoot.Members.OfType().ToList(); foreach (var ns in namespacesToProcess) { var nsName = ns.Name.ToString(); logger.AddLog($"Found original namespace: {nsName}", LogLevel.Debug); foreach (var cls in ns.Members.OfType()) { logger.AddLog($" Class in original: {cls.Identifier}", LogLevel.Debug); logger.AddLog(" Fields and Properties in original class:", LogLevel.Debug); // Log fields foreach (var field in cls.Members.OfType()) { foreach (var variable in field.Declaration.Variables) { logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug); } } // Log properties foreach (var prop in cls.Members.OfType()) { logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug); } foreach (var member in cls.Members) { switch (member) { case MethodDeclarationSyntax method: logger.AddLog($" Method in original: {method.Identifier}", LogLevel.Debug); break; case PropertyDeclarationSyntax prop: logger.AddLog($" Property in original: {prop.Identifier}", LogLevel.Debug); break; } } } } var newMembers = new List(); foreach (var ns in namespacesToProcess) { var nsName = ns.Name.ToString(); logger.AddLog($"Processing namespace: {nsName}", LogLevel.Debug); if (llmNamespaces.TryGetValue(nsName, out var llmNs)) { logger.AddLog($"Found matching LLM namespace for: {nsName}", LogLevel.Debug); var processedNs = ProcessNamespace(ns, llmNs, logger); newMembers.Add(processedNs); } else { logger.AddLog($"No matching LLM namespace found for: {nsName}, keeping original", LogLevel.Debug); newMembers.Add(ns); } } // Add new namespaces from LLM code foreach (var llmNs in llmNamespaces.Values) { var nsName = llmNs.Name.ToString(); if (!namespacesToProcess.Any(ns => ns.Name.ToString() == nsName)) { logger.AddLog($"Adding new namespace from LLM: {nsName}", LogLevel.Debug); newMembers.Add(llmNs); } } return originalRoot.WithMembers(SyntaxFactory.List(newMembers)); } private IEnumerable GetTopLevelMembers(CompilationUnitSyntax root) { return root.Members.Where(m => !(m is NamespaceDeclarationSyntax)); } private string FindBestNamespaceForMembers( IEnumerable members, CompilationUnitSyntax originalRoot, LogViewModel logger) { var methodsByClass = members.OfType() .ToDictionary( c => c.Identifier.ToString(), c => c.Members.OfType() .Select(m => m.Identifier.ToString()) .ToHashSet() ); foreach (var ns in originalRoot.Members.OfType()) { foreach (var cls in ns.Members.OfType()) { var className = cls.Identifier.ToString(); foreach (var method in cls.Members.OfType()) { if (methodsByClass.Any(kvp => kvp.Value.Contains(method.Identifier.ToString()))) { var nsName = ns.Name.ToString(); logger.AddLog($"Found matching method {method.Identifier} in namespace {nsName}", LogLevel.Debug); // Registrar el namespace para la clase que contiene el método coincidente var matchingClass = methodsByClass.First(kvp => kvp.Value.Contains(method.Identifier.ToString())).Key; _classNamespaceMapping.AddMapping(matchingClass, nsName); return nsName; } } } } // If no matching methods found, use first namespace var firstNamespace = originalRoot.Members.OfType().FirstOrDefault(); if (firstNamespace != null) { logger.AddLog($"No matching methods found, using first namespace: {firstNamespace.Name}", LogLevel.Debug); return firstNamespace.Name.ToString(); } logger.AddLog("No namespaces found in original code!", LogLevel.Warning); return "DefaultNamespace"; } private NamespaceDeclarationSyntax ProcessNamespace(NamespaceDeclarationSyntax original, NamespaceDeclarationSyntax llm, LogViewModel logger) { logger.AddLog($"Processing classes in namespace: {original.Name}", LogLevel.Debug); var classesToProcess = original.Members.OfType(); var llmClasses = llm.Members.OfType() .ToDictionary(c => c.Identifier.ToString()); var newMembers = new List(); foreach (var cls in classesToProcess) { if (llmClasses.TryGetValue(cls.Identifier.ToString(), out var llmClass)) { // Process methods and properties within the class var processedClass = ProcessClass(cls, llmClass, logger); newMembers.Add(processedClass); } else { // Keep original class unchanged newMembers.Add(cls); } } // Add any new classes from LLM code foreach (var llmClass in llmClasses.Values) { if (!classesToProcess.Any(c => c.Identifier.ToString() == llmClass.Identifier.ToString())) { newMembers.Add(llmClass); } } return original.WithMembers(SyntaxFactory.List(newMembers)); } private ClassDeclarationSyntax ProcessClass(ClassDeclarationSyntax original, ClassDeclarationSyntax llm, LogViewModel logger) { logger.AddLog($"Processing class: {original.Identifier}", LogLevel.Debug); // Log original fields and properties logger.AddLog("Original class fields and properties:", LogLevel.Debug); foreach (var field in original.Members.OfType()) { foreach (var variable in field.Declaration.Variables) { logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug); } } foreach (var prop in original.Members.OfType()) { logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug); } // Log LLM fields and properties logger.AddLog("LLM class fields and properties:", LogLevel.Debug); foreach (var field in llm.Members.OfType()) { foreach (var variable in field.Declaration.Variables) { logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug); } } foreach (var prop in llm.Members.OfType()) { logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug); } var newMembers = new List(); var processedMembers = new HashSet(); var processedFields = new HashSet(); var processedProperties = new HashSet(); // Process existing fields first foreach (var member in original.Members) { if (member is FieldDeclarationSyntax originalField) { foreach (var variable in originalField.Declaration.Variables) { var fieldName = variable.Identifier.ToString(); var llmField = llm.Members.OfType() .FirstOrDefault(f => f.Declaration.Variables .Any(v => v.Identifier.ToString() == fieldName)); if (llmField != null) { logger.AddLog($" Updating field: {fieldName}", LogLevel.Debug); newMembers.Add(llmField); processedFields.Add(fieldName); } else { logger.AddLog($" Keeping original field: {fieldName}", LogLevel.Debug); newMembers.Add(originalField); processedFields.Add(fieldName); } break; // Process one field declaration at a time } } } // Add new fields from LLM foreach (var field in llm.Members.OfType()) { foreach (var variable in field.Declaration.Variables) { var fieldName = variable.Identifier.ToString(); if (!processedFields.Contains(fieldName)) { logger.AddLog($" Adding new field from LLM: {fieldName}", LogLevel.Debug); // Add comment to mark new field with separator var newField = field.WithLeadingTrivia( SyntaxFactory.TriviaList( SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// ----------------------------------------"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// Added: New field"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"))); newMembers.Add(newField); processedFields.Add(fieldName); break; } } } // Procesar primero las propiedades existentes foreach (var member in original.Members) { if (member is PropertyDeclarationSyntax originalProperty) { var propertyName = originalProperty.Identifier.ToString(); var llmProperty = llm.Members.OfType() .FirstOrDefault(p => p.Identifier.ToString() == propertyName); if (llmProperty != null) { logger.AddLog($" Updating property: {propertyName}", LogLevel.Debug); newMembers.Add(llmProperty); processedProperties.Add(propertyName); } else { logger.AddLog($" Keeping original property: {propertyName}", LogLevel.Debug); newMembers.Add(originalProperty); processedProperties.Add(propertyName); } } } // Añadir nuevas propiedades del LLM foreach (var member in llm.Members.OfType()) { var propertyName = member.Identifier.ToString(); if (!processedProperties.Contains(propertyName)) { logger.AddLog($" Adding new property from LLM: {propertyName}", LogLevel.Debug); // Add comment to mark new property with separator var newProperty = member.WithLeadingTrivia( SyntaxFactory.TriviaList( SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// ----------------------------------------"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// Added: New property"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"))); newMembers.Add(newProperty); processedProperties.Add(propertyName); } } // Procesar métodos como antes foreach (var member in original.Members) { if (member is MethodDeclarationSyntax originalMethod) { var methodName = originalMethod.Identifier.ToString(); var llmMethod = llm.Members.OfType() .FirstOrDefault(m => m.Identifier.ToString() == methodName); if (llmMethod != null) { logger.AddLog($" Found matching method: {methodName}", LogLevel.Debug); var processedMethod = ProcessMethod(originalMethod, llmMethod, logger); // Add comment to mark modified method with separator var modifiedMethod = processedMethod.WithLeadingTrivia( SyntaxFactory.TriviaList( SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// ----------------------------------------"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// Modified: Updated implementation"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"))); newMembers.Add(modifiedMethod); processedMembers.Add(methodName); } else { logger.AddLog($" Keeping original method: {methodName}", LogLevel.Debug); newMembers.Add(member); } } else if (!(member is PropertyDeclarationSyntax)) { newMembers.Add(member); } } // Añadir nuevos métodos del LLM como antes foreach (var member in llm.Members) { if (member is MethodDeclarationSyntax llmMethod && !processedMembers.Contains(llmMethod.Identifier.ToString())) { logger.AddLog($" Adding new method from LLM: {llmMethod.Identifier}", LogLevel.Debug); // Add comment to mark new method with separator var newMethod = llmMethod.WithLeadingTrivia( SyntaxFactory.TriviaList( SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// ----------------------------------------"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"), SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, "// Added: New method"), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\r\n"))); newMembers.Add(newMethod); } } return original.WithMembers(SyntaxFactory.List(newMembers)); } private MethodDeclarationSyntax ProcessMethod(MethodDeclarationSyntax original, MethodDeclarationSyntax llm, LogViewModel logger) { var methodName = original.Identifier.ToString(); logger.AddLog($" Processing method: {methodName}", LogLevel.Debug); var llmBody = llm.Body?.ToString() ?? ""; logger.AddLog($" Original signature: {original.Modifiers} {original.ReturnType} {methodName}({string.Join(", ", original.ParameterList.Parameters)})", LogLevel.Debug); logger.AddLog($" LLM signature: {llm.Modifiers} {llm.ReturnType} {methodName}({string.Join(", ", llm.ParameterList.Parameters)})", LogLevel.Debug); if (llmBody.Contains(CONTINUATION_MARKER)) { logger.AddLog(" Found continuation marker in LLM code", LogLevel.Debug); var originalBody = original.Body?.ToString() ?? ""; var llmLines = llmBody.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var lastLlmLine = llmLines .Take(Array.FindIndex(llmLines, l => l.Contains(CONTINUATION_MARKER))) .Where(l => !string.IsNullOrWhiteSpace(l)) .LastOrDefault(); if (lastLlmLine != null) { logger.AddLog($" Last LLM line before marker: {lastLlmLine}", LogLevel.Debug); var originalLines = originalBody.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var continuationIndex = Array.FindIndex(originalLines, l => l.Trim() == lastLlmLine.Trim()); if (continuationIndex >= 0) { logger.AddLog($" Found continuation point at line {continuationIndex + 1}", LogLevel.Debug); var newBody = string.Join(Environment.NewLine, llmLines.Take(Array.FindIndex(llmLines, l => l.Contains(CONTINUATION_MARKER))) .Concat(originalLines.Skip(continuationIndex + 1))); logger.AddLog(" Successfully merged method bodies", LogLevel.Debug); return llm.WithBody(SyntaxFactory.Block(SyntaxFactory.ParseStatement(newBody))); } else { logger.AddLog(" Could not find continuation point in original code", LogLevel.Warning); } } } else { logger.AddLog(" Using complete LLM method implementation", LogLevel.Debug); } return llm; } }