diff --git a/CodePlay.Core/Validators/AutoFixEngine.cs b/CodePlay.Core/Validators/AutoFixEngine.cs new file mode 100644 index 0000000..475738c --- /dev/null +++ b/CodePlay.Core/Validators/AutoFixEngine.cs @@ -0,0 +1,213 @@ +using CodePlay.Core.Interfaces; +using CodePlay.Core.Models; +using CodePlay.Core.Common; + +namespace CodePlay.Core.Validators; + +/// +/// 自动修复引擎 +/// +public class AutoFixEngine : IAutoFixEngine +{ + /// + /// 尝试修复编译错误 + /// + public Task FixAsync(string code, List errors, int round, CancellationToken cancellationToken = default) + { + var result = new FixResult + { + CanFix = false, + RemainingErrors = new List() + }; + + if (errors == null || errors.Count == 0) + { + result.CanFix = true; + result.FixedCode = code; + return Task.FromResult(result); + } + + var fixedCode = code; + var remainingErrors = new List(); + + switch (round) + { + case 1: + // 第 1 轮:修复导入/using 语句 + result = FixRound1(code, errors); + break; + + case 2: + // 第 2 轮:修复类型映射 + result = FixRound2(code, errors); + break; + + case 3: + // 第 3 轮:修复 API 调用 + result = FixRound3(code, errors); + break; + + default: + result.RemainingErrors = errors; + break; + } + + return Task.FromResult(result); + } + + /// + /// 第 1 轮:修复导入/using 语句 + /// + private FixResult FixRound1(string code, List errors) + { + var result = new FixResult + { + CanFix = false, + RemainingErrors = new List() + }; + + var needsSystemUsing = false; + var needsCollectionsUsing = false; + var needsLinqUsing = false; + + foreach (var error in errors) + { + if (error.ErrorId == "CS0246" || error.ErrorId == "CS0103") + { + // 类型或命名空间找不到 + if (error.Message.Contains("Console")) + { + needsSystemUsing = true; + } + else if (error.Message.Contains("List") || error.Message.Contains("Dictionary")) + { + needsCollectionsUsing = true; + } + else if (error.Message.Contains("LINQ") || error.Message.Contains("var")) + { + needsLinqUsing = true; + } + else + { + result.RemainingErrors.Add(error); + } + } + else + { + result.RemainingErrors.Add(error); + } + } + + // 添加缺失的 using + var fixedCode = code; + var fixDescription = new StringBuilder(); + + if (needsSystemUsing && !code.Contains("using System;")) + { + fixedCode = fixedCode.Insert(0, "using System;\n"); + fixDescription.Append("Added using System; "); + } + + if (needsCollectionsUsing && !code.Contains("using System.Collections.Generic;")) + { + fixedCode = fixedCode.Insert(0, "using System.Collections.Generic;\n"); + fixDescription.Append("Added using System.Collections.Generic;"); + } + + if (needsLinqUsing && !code.Contains("using System.Linq;")) + { + fixedCode = fixedCode.Insert(0, "using System.Linq;\n"); + fixDescription.Append("Added using System.Linq;"); + } + + if (fixDescription.Length > 0) + { + result.CanFix = true; + result.FixedCode = fixedCode; + result.FixDescription = fixDescription.ToString(); + } + else + { + result.CanFix = false; + result.RemainingErrors = errors; + } + + return result; + } + + /// + /// 第 2 轮:修复类型映射 + /// + private FixResult FixRound2(string code, List errors) + { + var result = new FixResult + { + CanFix = false, + RemainingErrors = new List() + }; + + var fixedCode = code; + var hasFixes = false; + + foreach (var error in errors) + { + // Java 到 C# 的类型映射问题 + if (error.ErrorId == "CS0246") + { + if (error.Message.Contains("String")) + { + fixedCode = fixedCode.Replace("String", "string"); + hasFixes = true; + } + else if (error.Message.Contains("ArrayList")) + { + fixedCode = fixedCode.Replace("ArrayList", "List"); + hasFixes = true; + } + else if (error.Message.Contains("HashMap")) + { + fixedCode = fixedCode.Replace("HashMap", "Dictionary"); + hasFixes = true; + } + else + { + result.RemainingErrors.Add(error); + } + } + else + { + result.RemainingErrors.Add(error); + } + } + + if (hasFixes) + { + result.CanFix = true; + result.FixedCode = fixedCode; + result.FixDescription = "Applied type mapping fixes"; + } + else + { + result.RemainingErrors = errors; + } + + return result; + } + + /// + /// 第 3 轮:修复 API 调用 + /// + private FixResult FixRound3(string code, List errors) + { + var result = new FixResult + { + CanFix = false, + RemainingErrors = errors + }; + + // 这轮通常是复杂修复,MVP 版本暂不实现 + // 可以考虑修复一些常见的 API 调用差异 + + return result; + } +} diff --git a/CodePlay.Core/Validators/CSharpCompilerValidator.cs b/CodePlay.Core/Validators/CSharpCompilerValidator.cs new file mode 100644 index 0000000..dfb6ff4 --- /dev/null +++ b/CodePlay.Core/Validators/CSharpCompilerValidator.cs @@ -0,0 +1,109 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using CodePlay.Core.Interfaces; +using CodePlay.Core.Models; +using CodePlay.Core.Common; + +namespace CodePlay.Core.Validators; + +/// +/// C# 编译验证器 +/// +public class CSharpCompilerValidator : ICompilerValidator +{ + /// + /// 编译并验证 C# 代码 + /// + public async Task ValidateAsync(string code, LanguageType language, CancellationToken cancellationToken = default) + { + if (language != LanguageType.CSharp) + { + throw new ArgumentException("This validator only supports C#", nameof(language)); + } + + var result = new ValidationResult + { + Passed = false, + RoundsExecuted = 0, + NeedsManualReview = false, + CompilationErrors = new List(), + ValidationLog = new List() + }; + + result.ValidationLog.Add($"Starting compilation validation at {DateTime.UtcNow:HH:mm:ss.fff}"); + + try + { + // 创建语法树 + var syntaxTree = CSharpSyntaxTree.ParseText(code, cancellationToken: cancellationToken); + + // 创建编译 + var compilation = CSharpCompilation.Create( + "CodePlayValidation", + new[] { syntaxTree }, + new[] + { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Collections.Generic.List<>).Assembly.Location), + }, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + // emit 到内存流 + using var stream = new MemoryStream(); + var emitResult = compilation.Emit(stream, cancellationToken: cancellationToken); + + result.RoundsExecuted = 1; + + if (emitResult.Success) + { + result.Passed = true; + result.ValidationLog.Add("Compilation succeeded"); + } + else + { + result.Passed = false; + result.NeedsManualReview = false; + + // 收集诊断信息 + foreach (var diagnostic in emitResult.Diagnostics) + { + if (diagnostic.Severity == DiagnosticSeverity.Error) + { + result.CompilationErrors.Add(new CompilationError + { + ErrorId = diagnostic.Id, + Message = diagnostic.GetMessage(), + LineNumber = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1, + ColumnNumber = diagnostic.Location.GetLineSpan().StartLinePosition.Character + 1, + IsError = true + }); + + result.ValidationLog.Add($"Error: {diagnostic.GetMessage()}"); + } + else if (diagnostic.Severity == DiagnosticSeverity.Warning) + { + result.CompilationErrors.Add(new CompilationError + { + ErrorId = diagnostic.Id, + Message = diagnostic.GetMessage(), + LineNumber = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1, + ColumnNumber = diagnostic.Location.GetLineSpan().StartLinePosition.Character + 1, + IsError = false + }); + + result.ValidationLog.Add($"Warning: {diagnostic.GetMessage()}"); + } + } + } + } + catch (Exception ex) + { + result.ValidationLog.Add($"Compilation failed with exception: {ex.Message}"); + result.NeedsManualReview = true; + } + + return await Task.FromResult(result); + } +}