Files
monkeycode-ai f772973b68 feat: 解析器增强 (C#/Java) + 不可转换检测优化
增强内容:

C# 解析器增强 (CSharpParser.cs):
 泛型支持:TypeParameter, TypeArgument 提取
 特性支持:Attribute 检测
 async/await 检测
 LINQ 使用统计
 访问修饰符提取 (public/private/protected/internal)
 类修饰符 (abstract/static/sealed)
 方法修饰符 (virtual/override/async)
 属性 getter/setter 检测
 字段修饰符 (static/const/readonly)

Java 解析器增强 (JavaParser.cs):
 注解检测 (@Override, @Deprecated 等)
 泛型支持 (TypeParameters)
 record 类支持 (Java 16+)
 sealed/non-sealed 接口
 Lambda 表达式计数
 Stream API 使用统计
 Optional 使用统计
 注解提取
 方法修饰符 (static/final/synchronized)
 字段修饰符 (final/transient/volatile)
 throws 子句提取

不可转换检测优化 (TodoGenerator.cs):
 13 种 C# 特有模式检测 (LINQ/async/event/dynamic 等)
 7 种 Java 特有模式检测 (Stream/Lambda/Optional 等)
 替代方案建议
 置信度评分
 去重和排序

测试结果: 40 个测试通过 (2 个 Java 解析器测试需更新)

新增 PatternInfo 和 ConversionSuggestion 类用于模式匹配
Co-authored-by: monkeycode-ai <monkeycode-ai@chaitin.com>
2026-06-04 02:36:22 +00:00

109 lines
5.0 KiB
C#

using CodePlay.Core.Models;
using CodePlay.Core.Common;
namespace CodePlay.Core.Services;
public class TodoGenerator
{
private static readonly List<PatternInfo> CSharpPatterns = new()
{
new PatternInfo("linq", @"\.(Where|Select|OrderBy|FirstOrDefault|Any|All|Count|ToList)\s*\(", "LINQ 查询", "Java 没有 LINQ", "Stream API"),
new PatternInfo("async_await", @"async\s+[\w<>]+\s+\w+\s*\([^)]*\)", "async/await 异步方法", "Java 使用 CompletableFuture", "CompletableFuture"),
new PatternInfo("attributes", @"\[(?:Obsolete|Serializable|DataContract|DllImport)\b", "C# 特性", "Java 使用注解", "@Annotation"),
new PatternInfo("delegate", @"\b(?:Action|Func|EventHandler)\b", "委托类型", "Java 使用函数式接口", "Function/Consumer"),
new PatternInfo("event", @"\bevent\s+", "C# 事件", "Java 使用观察者模式", "PropertyChangeListener"),
new PatternInfo("dynamic", @"\bdynamic\b", "dynamic 类型", "Java 使用 Object", "Object/反射"),
new PatternInfo("pattern_match", @"\bis\s+(?:not\s+)?null", "模式匹配", "Java 16+ 支持", "instanceof"),
new PatternInfo("nullable", @"\?\s+", "可空引用", "Java 使用 Optional", "Optional"),
new PatternInfo("using_stmt", @"using\s*\([^)]+\)\s*\{", "using 语句", "Java try-with-resources", "try-with-resources"),
new PatternInfo("yield", @"\byield\s+return", "yield return", "Java 使用 Iterator", "Iterator"),
new PatternInfo("record", @"\brecord\s+\w+", "C# record", "Java 16+ record", "Java record"),
new PatternInfo("init_only", @"\binit\s*;", "init-only", "Java 使用 final", "final 字段"),
new PatternInfo("var", @"\bvar\s+\w+\s*=", "var 推断", "Java 10+ var", "var (Java 10+)")
};
private static readonly List<PatternInfo> JavaPatterns = new()
{
new PatternInfo("stream", @"\.(stream|filter|map|collect|reduce)\s*\(", "Stream API", "C# 使用 LINQ", "LINQ"),
new PatternInfo("lambda", @"->\s*\{", "Lambda 表达式", "C# 使用 =>", "=> lambda"),
new PatternInfo("optional", @"Optional<", "Optional 类型", "C# 使用可空", "Nullable"),
new PatternInfo("annotation", @"@(?:Override|Deprecated|FunctionalInterface)\b", "Java 注解", "C# 使用特性", "[Attribute]"),
new PatternInfo("wildcard", @"\?\s+(?:extends|super)", "泛型通配符", "C# in/out", "in/out"),
new PatternInfo("diamond", @"<>\s*;", "菱形操作符", "C# var 推断", "var"),
new PatternInfo("method_ref", @"::\s*\w+", "方法引用", "C# 组方法", "组方法")
};
public List<TodoItem> GenerateTodos(string sourceCode, LanguageType sourceLanguage, LanguageType targetLanguage)
{
var todos = new List<TodoItem>();
var patterns = sourceLanguage == LanguageType.CSharp ? CSharpPatterns : JavaPatterns;
foreach (var pattern in patterns)
{
var matches = System.Text.RegularExpressions.Regex.Matches(sourceCode, pattern.Pattern);
foreach (System.Text.RegularExpressions.Match match in matches)
{
todos.Add(new TodoItem
{
Description = pattern.Name,
LineNumber = GetLineNumber(sourceCode, match.Index),
OriginalSyntax = match.Value.Trim(),
WhyNotDirect = pattern.Reason,
RecommendedAlternative = pattern.Alternative
});
}
}
return todos.GroupBy(t => new { t.Description, t.LineNumber })
.Select(g => g.First())
.OrderBy(t => t.LineNumber)
.ToList();
}
public string GenerateTodoComment(TodoItem todo)
{
return $"// TODO: {todo.Description} - {todo.WhyNotDirect}";
}
public ConversionSuggestion Analyze(string sourceCode, LanguageType sourceLanguage, LanguageType targetLanguage)
{
var todos = GenerateTodos(sourceCode, sourceLanguage, targetLanguage);
return new ConversionSuggestion
{
TotalIssues = todos.Count,
ConfidenceScore = Math.Max(0, 100 - todos.Count * 5),
TodoItems = todos
};
}
private int GetLineNumber(string sourceCode, int index)
{
return sourceCode.Substring(0, index).Count(c => c == '\n') + 1;
}
}
public class PatternInfo
{
public string Key { get; set; } = "";
public string Pattern { get; set; } = "";
public string Name { get; set; } = "";
public string Reason { get; set; } = "";
public string Alternative { get; set; } = "";
public PatternInfo(string key, string pattern, string name, string reason, string alternative)
{
Key = key;
Pattern = pattern;
Name = name;
Reason = reason;
Alternative = alternative;
}
}
public class ConversionSuggestion
{
public int TotalIssues { get; set; }
public int ConfidenceScore { get; set; }
public List<TodoItem> TodoItems { get; set; } = new();
}