CodeMerger/cCodeMerger.cs

567 lines
25 KiB
C#

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<string, string> ClassToNamespace { get; } = new Dictionary<string, string>();
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<string> Diagnostics { get; set; } = new List<string>();
}
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<NamespaceDeclarationSyntax>()
.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<string, NamespaceDeclarationSyntax>();
// Log and collect LLM namespaces
foreach (var ns in llmRoot.Members.OfType<NamespaceDeclarationSyntax>())
{
var nsName = ns.Name.ToString();
logger.AddLog($"Found LLM namespace: {nsName}", LogLevel.Debug);
llmNamespaces[nsName] = ns;
foreach (var cls in ns.Members.OfType<ClassDeclarationSyntax>())
{
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<FieldDeclarationSyntax>())
{
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<PropertyDeclarationSyntax>())
{
logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug);
}
foreach (var method in cls.Members.OfType<MethodDeclarationSyntax>())
{
logger.AddLog($" Method: {method.Identifier}", LogLevel.Debug);
}
}
}
logger.AddLog("\nAnalyzing original code structure:", LogLevel.Debug);
var namespacesToProcess = originalRoot.Members.OfType<NamespaceDeclarationSyntax>().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<ClassDeclarationSyntax>())
{
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<FieldDeclarationSyntax>())
{
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<PropertyDeclarationSyntax>())
{
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<MemberDeclarationSyntax>();
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<MemberDeclarationSyntax> GetTopLevelMembers(CompilationUnitSyntax root)
{
return root.Members.Where(m => !(m is NamespaceDeclarationSyntax));
}
private string FindBestNamespaceForMembers(
IEnumerable<MemberDeclarationSyntax> members,
CompilationUnitSyntax originalRoot,
LogViewModel logger)
{
var methodsByClass = members.OfType<ClassDeclarationSyntax>()
.ToDictionary(
c => c.Identifier.ToString(),
c => c.Members.OfType<MethodDeclarationSyntax>()
.Select(m => m.Identifier.ToString())
.ToHashSet()
);
foreach (var ns in originalRoot.Members.OfType<NamespaceDeclarationSyntax>())
{
foreach (var cls in ns.Members.OfType<ClassDeclarationSyntax>())
{
var className = cls.Identifier.ToString();
foreach (var method in cls.Members.OfType<MethodDeclarationSyntax>())
{
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<NamespaceDeclarationSyntax>().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<ClassDeclarationSyntax>();
var llmClasses = llm.Members.OfType<ClassDeclarationSyntax>()
.ToDictionary(c => c.Identifier.ToString());
var newMembers = new List<MemberDeclarationSyntax>();
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<FieldDeclarationSyntax>())
{
foreach (var variable in field.Declaration.Variables)
{
logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug);
}
}
foreach (var prop in original.Members.OfType<PropertyDeclarationSyntax>())
{
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<FieldDeclarationSyntax>())
{
foreach (var variable in field.Declaration.Variables)
{
logger.AddLog($" Field: {variable.Identifier} : {field.Declaration.Type}", LogLevel.Debug);
}
}
foreach (var prop in llm.Members.OfType<PropertyDeclarationSyntax>())
{
logger.AddLog($" Property: {prop.Identifier} : {prop.Type}", LogLevel.Debug);
}
var newMembers = new List<MemberDeclarationSyntax>();
var processedMembers = new HashSet<string>();
var processedFields = new HashSet<string>();
var processedProperties = new HashSet<string>();
// 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<FieldDeclarationSyntax>()
.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<FieldDeclarationSyntax>())
{
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<PropertyDeclarationSyntax>()
.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<PropertyDeclarationSyntax>())
{
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<MethodDeclarationSyntax>()
.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;
}
}