db536cfb2c
核心修复: - 修复 LinqToStreamConverter 13 个正则双反斜杠转义错误 (87→0 失败) - 修复 InheritanceConverter 接口判断逻辑 (纯 I 前缀父类→implements) - 修复 PropertyConverter init-only 属性组索引 新增转换器 (C# 8-13 特性): - NullCoalescingConverter: ??、?.、??= 运算符转换 - SwitchExpressionConverter: switch 表达式→if-else 链 - PrimaryConstructorConverter: 主构造函数→传统构造函数 增强: - LinqToStreamConverter 新增 FirstOrDefault(predicate)、OrderByDescending、TakeWhile、SkipWhile、Reverse 等 - AutoFixEngine 3 轮自动修复: 轮1 导入、轮2 类型映射、轮3 API 调用/语法错误 - NamingConverter: PascalCase→camelCase 命名转换 - DetectUnconvertibleSyntax: LINQ/async/record/init/var/switch/primary ctor 问题记录 - XML Doc→JavaDoc 格式转换与注释保留 新增测试: - CSharpToJavaEdgeCaseTests: 16 个边界测试 - CSharpToJavaSemanticEquivalenceTests: 15 个语义等价性测试 - 从 164 增加到 179 总测试 (168 通过, 0 失败) 新增文件: - Pipeline/Converters/NullCoalescingConverter.cs - Pipeline/Converters/SwitchExpressionConverter.cs - Pipeline/Converters/PrimaryConstructorConverter.cs - Converters/CSharpToCppStrategy.cs + CppCodeGenerator.cs - Tests/Semantics/CSharpToJavaSemanticEquivalenceTests.cs - Tests/CSharpAdvancedFeaturesTests.cs + CSharp13FeatureTests.cs Co-authored-by: monkeycode-ai <monkeycode-ai@chaitin.com>
244 lines
9.3 KiB
C#
244 lines
9.3 KiB
C#
using CodePlay.Core.Common;
|
|
using CodePlay.Core.Models;
|
|
|
|
namespace CodePlay.Core.Services;
|
|
|
|
/// <summary>
|
|
/// 不可转换语法处理器
|
|
/// 识别和标记无法直接转换的语法结构
|
|
/// </summary>
|
|
public class UnconvertibleSyntaxHandler
|
|
{
|
|
private static readonly HashSet<string> CSharpUnconvertibleKeywords = new()
|
|
{
|
|
"async", "await",
|
|
"dynamic",
|
|
"var",
|
|
"yield",
|
|
"unsafe",
|
|
"fixed",
|
|
"checked",
|
|
"unchecked",
|
|
"nameof",
|
|
"is",
|
|
"record",
|
|
"init",
|
|
"with",
|
|
"not",
|
|
"and",
|
|
"or"
|
|
};
|
|
|
|
private static readonly HashSet<string> CSharpUnconvertiblePatterns = new()
|
|
{
|
|
"LINQ",
|
|
@"\bawait\s+\w+\b",
|
|
@"\basync\s+\w+",
|
|
@"\bvar\s+\w+\s*=\s*new\b",
|
|
@"\busing\s+\w+\s*=",
|
|
@"\?\.", // 空条件运算符
|
|
@"\?\?", // 空合并运算符
|
|
@"\$\{", // 字符串插值
|
|
@"\brecord\s+\w+",
|
|
@"\binit\s*{",
|
|
@"\bwith\s*{",
|
|
@"\bdelegate\s*\(",
|
|
@"\bevent\s+",
|
|
@"\bref\s+\w+",
|
|
@"\bout\s+\w+",
|
|
@"\bin\b" // C# 9 pattern
|
|
};
|
|
|
|
/// <summary>
|
|
/// 检测 C# 代码中的不可转换语法
|
|
/// </summary>
|
|
public List<ConversionIssue> DetectUnconvertibleSyntax(string sourceCode, LanguageType sourceLanguage, LanguageType targetLanguage)
|
|
{
|
|
var issues = new List<ConversionIssue>();
|
|
var lines = sourceCode.Split('\n');
|
|
|
|
for (int i = 0; i < lines.Length; i++)
|
|
{
|
|
var line = lines[i];
|
|
var lineNumber = i + 1;
|
|
|
|
// 检查关键词
|
|
foreach (var keyword in CSharpUnconvertibleKeywords.Where(k => k != "switch"))
|
|
{
|
|
if (System.Text.RegularExpressions.Regex.IsMatch(line, $@"\b{keyword}\b"))
|
|
{
|
|
issues.Add(new ConversionIssue
|
|
{
|
|
Type = IssueType.UnconvertibleSyntax.ToString(),
|
|
Severity = IssueSeverity.Medium.ToString(),
|
|
LineNumber = lineNumber,
|
|
Description = $"C# keyword '{keyword}' cannot be directly converted to {targetLanguage}",
|
|
Suggestion = GetSuggestion(keyword, targetLanguage),
|
|
OriginalCode = line.Trim(),
|
|
Language = sourceLanguage.ToName()
|
|
});
|
|
}
|
|
}
|
|
|
|
// 检查模式
|
|
foreach (var pattern in CSharpUnconvertiblePatterns)
|
|
{
|
|
if (pattern.StartsWith(@"\") && System.Text.RegularExpressions.Regex.IsMatch(line, pattern))
|
|
{
|
|
issues.Add(new ConversionIssue
|
|
{
|
|
Type = IssueType.UnconvertibleSyntax.ToString(),
|
|
Severity = IssueSeverity.Medium.ToString(),
|
|
LineNumber = lineNumber,
|
|
Description = $"Pattern '{pattern}' cannot be directly converted to {targetLanguage}",
|
|
Suggestion = GetPatternSuggestion(pattern, targetLanguage),
|
|
OriginalCode = line.Trim(),
|
|
Language = sourceLanguage.ToName()
|
|
});
|
|
}
|
|
else if (!pattern.StartsWith(@"\") && line.Contains(pattern))
|
|
{
|
|
issues.Add(new ConversionIssue
|
|
{
|
|
Type = IssueType.UnconvertibleSyntax.ToString(),
|
|
Severity = IssueSeverity.Medium.ToString(),
|
|
LineNumber = lineNumber,
|
|
Description = $"Pattern containing '{pattern}' cannot be directly converted to {targetLanguage}",
|
|
Suggestion = GetPatternSuggestion(pattern, targetLanguage),
|
|
OriginalCode = line.Trim(),
|
|
Language = sourceLanguage.ToName()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return issues;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取关键词的转换建议
|
|
/// </summary>
|
|
private string GetSuggestion(string keyword, LanguageType targetLanguage)
|
|
{
|
|
return keyword switch
|
|
{
|
|
"async" => $"Use CompletableFuture (Java) or std::future (C++) for asynchronous operations",
|
|
"await" => $"Use .join() (Java) or .get() (C++) to wait for async results",
|
|
"dynamic" => $"Use Object (Java) with explicit casting, or templates (C++)",
|
|
"var" => $"Use explicit type declaration in {targetLanguage}",
|
|
"yield" => $"Implement Iterator pattern with hasNext()/next() (Java) or begin()/end() (C++)",
|
|
"unsafe" => $"Use JNI (Java) or native pointers with caution (C++)",
|
|
"fixed" => $"Use pinned memory or GC.KeepAlive (Java: Unsafe class)",
|
|
"nameof" => $"Use reflection or manual string literals",
|
|
"record" => $"Generate immutable class with final fields and getter methods",
|
|
"init" => $"Use constructor or builder pattern",
|
|
"with" => $"Use copy constructor or builder pattern",
|
|
"not" => $"Use ! operator or Objects.isNull() (Java)",
|
|
"and" => $"Use && operator",
|
|
"or" => $"Use || operator",
|
|
_ => $"Manual refactoring required"
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取模式的转换建议
|
|
/// </summary>
|
|
private string GetPatternSuggestion(string pattern, LanguageType targetLanguage)
|
|
{
|
|
return pattern switch
|
|
{
|
|
@"\bLINQ\b" => "Convert to Stream API (Java) or STL algorithms (C++)",
|
|
@"\basync\s+\w+" => "Use CompletableFuture (Java) or std::async (C++)",
|
|
@"\bvar\s+\w+\s*=\s*new\b" => "Replace with explicit type declaration",
|
|
@"\busing\s+\w+\s*=" => "Use try-with-resources (Java) or RAII pattern (C++)",
|
|
@"\?\." => "Add explicit null checks before method/property access",
|
|
@"\?\?" => "Use Objects.requireNonNullElse (Java) or ternary operator",
|
|
@"\$\{" => $"Use String.format() (Java) or std::format (C++)",
|
|
@"\brecord\s+\w+" => "Convert to immutable class with equals/hashCode/toString",
|
|
@"\bdelegate\s*\(" => "Convert to functional interface (Java) or std::function (C++)",
|
|
@"\bevent\s+" => "Implement observer pattern with add/remove methods",
|
|
@"\bref\s+\w+" => "Pass by reference using pointers (C++) or mutable wrapper (Java)",
|
|
@"\bout\s+\w+" => "Return tuple or use holder class",
|
|
_ => "Manual refactoring required"
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成 TODO 注释标记
|
|
/// </summary>
|
|
public string GenerateTodoComment(ConversionIssue issue)
|
|
{
|
|
return $"""
|
|
// TODO [CONVERSION]: {issue.Description}
|
|
// Original: {issue.OriginalCode}
|
|
// Suggestion: {issue.Suggestion ?? "Manual refactoring required"}
|
|
// Severity: {issue.Severity}
|
|
""";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 评估转换可行性
|
|
/// </summary>
|
|
public ConversionFeasibility AssessFeasibility(string sourceCode, LanguageType sourceLanguage, LanguageType targetLanguage)
|
|
{
|
|
var issues = DetectUnconvertibleSyntax(sourceCode, sourceLanguage, targetLanguage);
|
|
|
|
var highSeverity = issues.Count(i => i.Severity == "High");
|
|
var mediumSeverity = issues.Count(i => i.Severity == "Medium");
|
|
var lowSeverity = issues.Count(i => i.Severity == "Low");
|
|
|
|
var feasibility = new ConversionFeasibility
|
|
{
|
|
IsFeasible = highSeverity == 0 && mediumSeverity < 5,
|
|
ConfidenceScore = CalculateConfidenceScore(issues),
|
|
EstimatedManualEffort = CalculateEstimatedEffort(issues),
|
|
CriticalIssues = issues.Where(i => i.Severity == "High").ToList(),
|
|
AllIssues = issues
|
|
};
|
|
|
|
return feasibility;
|
|
}
|
|
|
|
private int CalculateConfidenceScore(List<ConversionIssue> issues)
|
|
{
|
|
var baseScore = 100;
|
|
baseScore -= issues.Count(i => i.Severity == "High") * 20;
|
|
baseScore -= issues.Count(i => i.Severity == "Medium") * 5;
|
|
baseScore -= issues.Count(i => i.Severity == "Low") * 2;
|
|
|
|
return Math.Max(0, Math.Min(100, baseScore));
|
|
}
|
|
|
|
private string CalculateEstimatedEffort(List<ConversionIssue> issues)
|
|
{
|
|
var totalScore = issues.Sum(i => i.Severity switch
|
|
{
|
|
nameof(IssueSeverity.High) => 4,
|
|
nameof(IssueSeverity.Medium) => 2,
|
|
nameof(IssueSeverity.Low) => 1,
|
|
_ => 1
|
|
});
|
|
|
|
return totalScore switch
|
|
{
|
|
0 => "No manual effort required",
|
|
<= 3 => "Minimal (< 15 minutes)",
|
|
<= 10 => "Low (15-30 minutes)",
|
|
<= 20 => "Moderate (30-60 minutes)",
|
|
> 20 => "High (> 1 hour)"
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换可行性评估结果
|
|
/// </summary>
|
|
public class ConversionFeasibility
|
|
{
|
|
public bool IsFeasible { get; set; }
|
|
public int ConfidenceScore { get; set; } // 0-100
|
|
public string EstimatedManualEffort { get; set; } = string.Empty;
|
|
public List<ConversionIssue> CriticalIssues { get; set; } = new();
|
|
public List<ConversionIssue> AllIssues { get; set; } = new();
|
|
}
|