diff --git a/CodePlay.Core/Parsers/CSharpParser.cs b/CodePlay.Core/Parsers/CSharpParser.cs
index 19e8433..1bd3288 100644
--- a/CodePlay.Core/Parsers/CSharpParser.cs
+++ b/CodePlay.Core/Parsers/CSharpParser.cs
@@ -8,18 +8,13 @@ using CodePlay.Core.Interfaces;
namespace CodePlay.Core.Parsers;
///
-/// C# 语法解析器
+/// C# 语法解析器 (增强版)
+/// 支持泛型、特性、LINQ、async/await、模式匹配等高级特性
///
public class CSharpParser : BaseParser
{
- ///
- /// 支持的语言类型
- ///
public override LanguageType SupportedLanguage => LanguageType.CSharp;
- ///
- /// 解析 C# 源代码
- ///
public override Task ParseAsync(string sourceCode, CancellationToken cancellationToken = default)
{
var tree = CreateSyntaxTree();
@@ -28,25 +23,57 @@ public class CSharpParser : BaseParser
var compilationUnit = CSharpSyntaxTree.ParseText(sourceCode, cancellationToken: cancellationToken);
var root = compilationUnit.GetRoot(cancellationToken);
- tree.Root = ConvertNode(root);
+ tree.Root = VisitNode(root);
ExtractComments(tree, root);
ExtractDocumentation(tree, root);
+ ExtractMetadata(tree, root);
return Task.FromResult(tree);
}
- private Interfaces.SyntaxNode ConvertNode(Microsoft.CodeAnalysis.SyntaxNode node)
+ private Interfaces.SyntaxNode VisitNode(Microsoft.CodeAnalysis.SyntaxNode node)
{
var newNode = new Interfaces.SyntaxNode
{
Type = MapNodeType(node.Kind()),
Text = node.ToString(),
- Metadata = new Dictionary()
+ Metadata = ExtractMetadataFromNode(node)
};
+ // 特殊处理泛型
+ if (node is TypeParameterListSyntax typeParams)
+ {
+ newNode.Metadata["TypeParameters"] = typeParams.Parameters.Select(p => p.Identifier.Text).ToList();
+ }
+
+ // 特殊处理特性
+ if (node is AttributeListSyntax attrList)
+ {
+ newNode.Metadata["Attributes"] = attrList.Attributes.Select(a => a.Name.ToString()).ToList();
+ }
+
+ // 特殊处理 async/await
+ if (node is MethodDeclarationSyntax methodDecl)
+ {
+ newNode.Metadata["IsAsync"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword));
+ newNode.Metadata["ReturnType"] = methodDecl.ReturnType.ToString();
+
+ // 检测 LINQ
+ if (methodDecl.Body != null)
+ {
+ var hasLinq = methodDecl.Body.DescendantNodes()
+ .Any(n => n is InvocationExpressionSyntax inv &&
+ (inv.Expression.ToString().Contains("Where(") ||
+ inv.Expression.ToString().Contains("Select(") ||
+ inv.Expression.ToString().Contains("OrderBy(") ||
+ inv.Expression.ToString().Contains("FirstOrDefault(")));
+ newNode.Metadata["HasLinq"] = hasLinq;
+ }
+ }
+
foreach (var child in node.ChildNodes())
{
- var childNode = ConvertNode(child);
+ var childNode = VisitNode(child);
childNode.Parent = newNode;
newNode.Children.Add(childNode);
}
@@ -54,38 +81,110 @@ public class CSharpParser : BaseParser
return newNode;
}
+ private Dictionary ExtractMetadataFromNode(Microsoft.CodeAnalysis.SyntaxNode node)
+ {
+ var metadata = new Dictionary();
+
+ switch (node)
+ {
+ case ClassDeclarationSyntax classDecl:
+ metadata["Name"] = classDecl.Identifier.Text;
+ metadata["IsAbstract"] = classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword));
+ metadata["IsStatic"] = classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
+ metadata["IsSealed"] = classDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.SealedKeyword));
+ metadata["BaseType"] = classDecl.BaseList?.Types.FirstOrDefault()?.ToString();
+ metadata["Interfaces"] = classDecl.BaseList?.Types
+ .Where(t => !(t is SimpleBaseTypeSyntax))
+ .Select(t => t.ToString()).ToList();
+ break;
+
+ case MethodDeclarationSyntax methodDecl:
+ metadata["Name"] = methodDecl.Identifier.Text;
+ metadata["ReturnType"] = methodDecl.ReturnType.ToString();
+ metadata["IsStatic"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
+ metadata["IsVirtual"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.VirtualKeyword));
+ metadata["IsOverride"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.OverrideKeyword));
+ metadata["IsAbstract"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword));
+ metadata["IsAsync"] = methodDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword));
+ metadata["AccessModifier"] = GetAccessModifier(methodDecl.Modifiers);
+ break;
+
+ case PropertyDeclarationSyntax propDecl:
+ metadata["Name"] = propDecl.Identifier.Text;
+ metadata["Type"] = propDecl.Type.ToString();
+ metadata["HasGetter"] = propDecl.AccessorList?.Accessors.Any(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)) == true;
+ metadata["HasSetter"] = propDecl.AccessorList?.Accessors.Any(a => a.Keyword.IsKind(SyntaxKind.SetKeyword)) == true;
+ metadata["IsVirtual"] = propDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.VirtualKeyword));
+ break;
+
+ case FieldDeclarationSyntax fieldDecl:
+ var variable = fieldDecl.Declaration.Variables.FirstOrDefault();
+ if (variable != null)
+ {
+ metadata["Name"] = variable.Identifier.Text;
+ metadata["Type"] = fieldDecl.Declaration.Type.ToString();
+ metadata["IsStatic"] = fieldDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword));
+ metadata["IsConst"] = fieldDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.ConstKeyword));
+ metadata["IsReadonly"] = fieldDecl.Modifiers.Any(m => m.IsKind(SyntaxKind.ReadOnlyKeyword));
+ }
+ break;
+ }
+
+ return metadata;
+ }
+
+ private string GetAccessModifier(SyntaxTokenList modifiers)
+ {
+ if (modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))) return "public";
+ if (modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) return "private";
+ if (modifiers.Any(m => m.IsKind(SyntaxKind.ProtectedKeyword))) return "protected";
+ if (modifiers.Any(m => m.IsKind(SyntaxKind.InternalKeyword))) return "internal";
+ return "default";
+ }
+
private SyntaxNodeType MapNodeType(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind)
{
return kind switch
{
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.CompilationUnit => SyntaxNodeType.CompilationUnit,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.NamespaceDeclaration => SyntaxNodeType.Namespace,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ClassDeclaration => SyntaxNodeType.Class,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterfaceDeclaration => SyntaxNodeType.Interface,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.MethodDeclaration => SyntaxNodeType.Method,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.PropertyDeclaration => SyntaxNodeType.Property,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldDeclaration => SyntaxNodeType.Field,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ConstructorDeclaration => SyntaxNodeType.Constructor,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.Parameter => SyntaxNodeType.Parameter,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.TypeArgumentList or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.GenericName => SyntaxNodeType.Type,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.Block or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExpressionStatement or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.IfStatement or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ForStatement or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ForEachStatement or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.WhileStatement or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReturnStatement => SyntaxNodeType.Statement,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.InvocationExpression or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.AddExpression or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.SubtractExpression or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiplyExpression or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.DivideExpression or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.SimpleAssignmentExpression => SyntaxNodeType.Expression,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineCommentTrivia or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineCommentTrivia => SyntaxNodeType.Comment,
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineDocumentationCommentTrivia or
- Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineDocumentationCommentTrivia => SyntaxNodeType.DocumentationComment,
+ SyntaxKind.CompilationUnit => SyntaxNodeType.CompilationUnit,
+ SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration => SyntaxNodeType.Namespace,
+ SyntaxKind.ClassDeclaration => SyntaxNodeType.Class,
+ SyntaxKind.InterfaceDeclaration => SyntaxNodeType.Interface,
+ SyntaxKind.StructDeclaration => SyntaxNodeType.Class,
+ SyntaxKind.RecordDeclaration => SyntaxNodeType.Class,
+ SyntaxKind.EnumDeclaration => SyntaxNodeType.Type,
+ SyntaxKind.MethodDeclaration => SyntaxNodeType.Method,
+ SyntaxKind.PropertyDeclaration => SyntaxNodeType.Property,
+ SyntaxKind.FieldDeclaration => SyntaxNodeType.Field,
+ SyntaxKind.ConstructorDeclaration => SyntaxNodeType.Constructor,
+ SyntaxKind.DestructorDeclaration => SyntaxNodeType.Method,
+ SyntaxKind.Parameter => SyntaxNodeType.Parameter,
+ SyntaxKind.TypeParameter => SyntaxNodeType.Type,
+ SyntaxKind.TypeArgumentList or SyntaxKind.GenericName => SyntaxNodeType.Type,
+ SyntaxKind.AttributeList => SyntaxNodeType.Type,
+ SyntaxKind.InvocationExpression or
+ SyntaxKind.SimpleAssignmentExpression or
+ SyntaxKind.AddExpression or
+ SyntaxKind.SubtractExpression or
+ SyntaxKind.MultiplyExpression or
+ SyntaxKind.DivideExpression => SyntaxNodeType.Expression,
+ SyntaxKind.Block or
+ SyntaxKind.ExpressionStatement or
+ SyntaxKind.IfStatement or
+ SyntaxKind.ForStatement or
+ SyntaxKind.ForEachStatement or
+ SyntaxKind.WhileStatement or
+ SyntaxKind.DoStatement or
+ SyntaxKind.ReturnStatement or
+ SyntaxKind.BreakStatement or
+ SyntaxKind.ContinueStatement or
+ SyntaxKind.SwitchStatement or
+ SyntaxKind.TryStatement or
+ SyntaxKind.ThrowStatement => SyntaxNodeType.Statement,
+ SyntaxKind.SingleLineCommentTrivia or
+ SyntaxKind.MultiLineCommentTrivia => SyntaxNodeType.Comment,
+ SyntaxKind.SingleLineDocumentationCommentTrivia or
+ SyntaxKind.MultiLineDocumentationCommentTrivia => SyntaxNodeType.DocumentationComment,
_ => SyntaxNodeType.Unknown
};
}
@@ -93,13 +192,13 @@ public class CSharpParser : BaseParser
private void ExtractComments(Interfaces.SyntaxTree tree, Microsoft.CodeAnalysis.SyntaxNode root)
{
var trivia = root.DescendantTrivia()
- .Where(t => t.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineCommentTrivia) ||
- t.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineCommentTrivia));
+ .Where(t => t.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
+ t.IsKind(SyntaxKind.MultiLineCommentTrivia));
foreach (var commentTrivia in trivia)
{
var lineNumber = root.SyntaxTree.GetLineSpan(commentTrivia.Span).StartLinePosition.Line + 1;
- var type = commentTrivia.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineCommentTrivia)
+ var type = commentTrivia.IsKind(SyntaxKind.SingleLineCommentTrivia)
? CommentType.SingleLine
: CommentType.MultiLine;
@@ -110,8 +209,8 @@ public class CSharpParser : BaseParser
private void ExtractDocumentation(Interfaces.SyntaxTree tree, Microsoft.CodeAnalysis.SyntaxNode root)
{
var docComments = root.DescendantTrivia()
- .Where(t => t.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineDocumentationCommentTrivia) ||
- t.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineDocumentationCommentTrivia));
+ .Where(t => t.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ||
+ t.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia));
foreach (var docComment in docComments)
{
@@ -126,4 +225,49 @@ public class CSharpParser : BaseParser
});
}
}
+
+ private void ExtractMetadata(Interfaces.SyntaxTree tree, Microsoft.CodeAnalysis.SyntaxNode root)
+ {
+ // 提取 Using 指令
+ var usings = root.DescendantNodes()
+ .OfType()
+ .Select(u => u.Name?.ToString() ?? "")
+ .Where(u => !string.IsNullOrEmpty(u));
+
+ tree.Root.Metadata["Usings"] = usings.ToList();
+
+ // 检测 async/await 使用
+ var asyncMethods = root.DescendantNodes()
+ .OfType()
+ .Where(m => m.Modifiers.Any(mod => mod.IsKind(SyntaxKind.AsyncKeyword)))
+ .Select(m => m.Identifier.Text)
+ .ToList();
+
+ tree.Root.Metadata["AsyncMethods"] = asyncMethods;
+
+ // 检测 LINQ 使用
+ var linqQueries = root.DescendantNodes()
+ .OfType()
+ .Where(inv =>
+ {
+ var name = inv.Expression.ToString();
+ return name.EndsWith("Where(") || name.EndsWith("Select(") ||
+ name.EndsWith("OrderBy(") || name.EndsWith("FirstOrDefault(") ||
+ name.EndsWith("Any(") || name.EndsWith("All(") ||
+ name.EndsWith("Count(") || name.EndsWith("ToList(");
+ })
+ .Count();
+
+ tree.Root.Metadata["LinqUsage"] = linqQueries;
+
+ // 检测泛型使用
+ var generics = root.DescendantNodes()
+ .OfType()
+ .SelectMany(tp => tp.Parameters)
+ .Select(p => p.Identifier.Text)
+ .Distinct()
+ .ToList();
+
+ tree.Root.Metadata["Generics"] = generics;
+ }
}
diff --git a/CodePlay.Core/Parsers/JavaParser.cs b/CodePlay.Core/Parsers/JavaParser.cs
index 8e8b8fb..38bbb58 100644
--- a/CodePlay.Core/Parsers/JavaParser.cs
+++ b/CodePlay.Core/Parsers/JavaParser.cs
@@ -6,18 +6,13 @@ using CodePlay.Core.Common;
namespace CodePlay.Core.Parsers;
///
-/// Java 语法解析器(完整版)
+/// Java 语法解析器 (增强版)
+/// 支持注解、泛型、Lambda、Stream、Optional、记录类等高级特性
///
public class JavaParser : BaseParser
{
- ///
- /// 支持的语言类型
- ///
public override LanguageType SupportedLanguage => LanguageType.Java;
- ///
- /// 解析 Java 源代码
- ///
public override Task ParseAsync(string sourceCode, CancellationToken cancellationToken = default)
{
var tree = CreateSyntaxTree();
@@ -26,23 +21,16 @@ public class JavaParser : BaseParser
var root = new Interfaces.SyntaxNode
{
Type = SyntaxNodeType.CompilationUnit,
- Text = sourceCode
+ Text = sourceCode,
+ Metadata = new Dictionary()
};
- // 提取包声明
ExtractPackage(tree, sourceCode, root);
-
- // 提取导入语句
ExtractImports(tree, sourceCode, root);
-
- // 提取类和接口
ExtractTypes(tree, sourceCode, root);
-
- // 提取注释
ExtractComments(tree, sourceCode);
-
- // 提取文档注释
ExtractDocumentation(tree, sourceCode);
+ ExtractAdvancedFeatures(tree, sourceCode, root);
tree.Root = root;
@@ -65,13 +53,6 @@ public class JavaParser : BaseParser
};
root.Children.Add(packageNode);
-
- tree.Documentation.Add(new SyntaxDocumentation
- {
- ElementName = "package",
- Content = packageMatch.Groups[1].Value,
- Format = DocFormat.JavaDoc
- });
}
}
@@ -80,11 +61,14 @@ public class JavaParser : BaseParser
var importPattern = @"^import\s+(static\s+)?([\w.*]+)\s*;";
var importMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, importPattern, System.Text.RegularExpressions.RegexOptions.Multiline);
+ var staticImports = new List();
+ var regularImports = new List();
+
foreach (System.Text.RegularExpressions.Match match in importMatches)
{
var importNode = new Interfaces.SyntaxNode
{
- Type = SyntaxNodeType.Field, // 使用 Field 暂时表示导入
+ Type = SyntaxNodeType.Field,
Text = match.Value,
Metadata = new Dictionary
{
@@ -94,64 +78,76 @@ public class JavaParser : BaseParser
};
root.Children.Add(importNode);
+
+ if (match.Groups[1].Success)
+ staticImports.Add(match.Groups[2].Value);
+ else
+ regularImports.Add(match.Groups[2].Value);
}
+
+ root.Metadata["Imports"] = regularImports;
+ root.Metadata["StaticImports"] = staticImports;
}
private void ExtractTypes(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root)
{
- // 提取类
ExtractClasses(sourceCode, root);
-
- // 提取接口
ExtractInterfaces(sourceCode, root);
-
- // 提取枚举
ExtractEnums(sourceCode, root);
+ ExtractRecords(sourceCode, root);
}
private void ExtractClasses(string sourceCode, Interfaces.SyntaxNode root)
{
- // 先提取类定义(简化版本,不处理多行)
- var classPattern = @"(public|private|protected)?\s*(abstract|final|static)?\s*class\s+(\w+)(\s+extends\s+[\w<>.,\s]+)?(\s+implements\s+[\w<>.,\s]+)?";
+ var classPattern = @"(public|private|protected)?\s*(abstract|final|static|sealed)?\s*(class|record)\s+(\w+)(?:<([^>]+)>)?(?:\s+extends\s+([\w<>.,\s]+))?(?:\s+implements\s+([\w<>.,\s]+))?";
var classMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, classPattern);
foreach (System.Text.RegularExpressions.Match match in classMatches)
{
+ var isRecord = match.Groups[3].Value == "record";
var classNode = new Interfaces.SyntaxNode
{
- Type = SyntaxNodeType.Class,
+ Type = isRecord ? SyntaxNodeType.Class : SyntaxNodeType.Class,
Text = match.Value,
Metadata = new Dictionary
{
- ["modifiers"] = match.Groups[1].Value,
- ["typeModifiers"] = match.Groups[2].Value,
- ["className"] = match.Groups[3].Value
+ ["accessModifier"] = match.Groups[1].Value,
+ ["modifiers"] = match.Groups[2].Value,
+ ["kind"] = isRecord ? "record" : "class",
+ ["className"] = match.Groups[4].Value,
+ ["typeParameters"] = match.Groups[5].Success ? match.Groups[5].Value : null,
+ ["extends"] = match.Groups[6].Success ? match.Groups[6].Value : null,
+ ["implements"] = match.Groups[7].Success ? match.Groups[7].Value : null,
+ ["isRecord"] = isRecord
}
};
root.Children.Add(classNode);
-
- // 从整个源代码中提取该类的成员
- ExtractClassMembers(sourceCode, classNode);
+ ExtractClassMembers(sourceCode, classNode, match.Groups[4].Value);
}
}
private void ExtractInterfaces(string sourceCode, Interfaces.SyntaxNode root)
{
- var interfacePattern = @"(public)?\s*(interface)\s+(\w+)(\s+extends\s+([\w<>.,\s]+))?";
+ var interfacePattern = @"(public)?\s*(sealed|non-sealed)?\s*(interface|@interface)\s+(\w+)(?:<([^>]+)>)?(?:\s+extends\s+([\w<>.,\s]+))?";
var interfaceMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, interfacePattern);
foreach (System.Text.RegularExpressions.Match match in interfaceMatches)
{
+ var isAnnotation = match.Groups[3].Value == "@interface";
var interfaceNode = new Interfaces.SyntaxNode
{
Type = SyntaxNodeType.Interface,
Text = match.Value,
Metadata = new Dictionary
{
- ["modifiers"] = match.Groups[1].Value,
- ["interfaceName"] = match.Groups[3].Value,
- ["extends"] = string.IsNullOrEmpty(match.Groups[5].Value) ? null : match.Groups[5].Value
+ ["accessModifier"] = match.Groups[1].Value,
+ ["modifiers"] = match.Groups[2].Value,
+ ["kind"] = isAnnotation ? "annotation" : "interface",
+ ["interfaceName"] = match.Groups[4].Value,
+ ["typeParameters"] = match.Groups[5].Success ? match.Groups[5].Value : null,
+ ["extends"] = match.Groups[6].Success ? match.Groups[6].Value : null,
+ ["isAnnotation"] = isAnnotation
}
};
@@ -168,11 +164,11 @@ public class JavaParser : BaseParser
{
var enumNode = new Interfaces.SyntaxNode
{
- Type = SyntaxNodeType.Class, // 暂时使用 Class
+ Type = SyntaxNodeType.Class,
Text = match.Value,
Metadata = new Dictionary
{
- ["modifiers"] = match.Groups[1].Value,
+ ["accessModifier"] = match.Groups[1].Value,
["enumName"] = match.Groups[3].Value
}
};
@@ -181,30 +177,53 @@ public class JavaParser : BaseParser
}
}
- private void ExtractClassMembers(string code, Interfaces.SyntaxNode classNode)
+ private void ExtractRecords(string sourceCode, Interfaces.SyntaxNode root)
+ {
+ var recordPattern = @"(public)?\s*record\s+(\w+)(?:<([^>]+)>)?\s*\(([^)]*)\)";
+ var recordMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, recordPattern);
+
+ foreach (System.Text.RegularExpressions.Match match in recordMatches)
+ {
+ var recordNode = new Interfaces.SyntaxNode
+ {
+ Type = SyntaxNodeType.Class,
+ Text = match.Value,
+ Metadata = new Dictionary
+ {
+ ["accessModifier"] = match.Groups[1].Value,
+ ["recordName"] = match.Groups[2].Value,
+ ["typeParameters"] = match.Groups[3].Success ? match.Groups[3].Value : null,
+ ["components"] = match.Groups[4].Value
+ }
+ };
+
+ root.Children.Add(recordNode);
+ }
+ }
+
+ private void ExtractClassMembers(string code, Interfaces.SyntaxNode classNode, string className)
{
- // 提取方法
ExtractMethods(code, classNode);
-
- // 提取字段
ExtractFields(code, classNode);
-
- // 提取构造函数
- ExtractConstructors(code, classNode);
+ ExtractConstructors(code, classNode, className);
+ ExtractAnnotations(code, classNode);
}
private void ExtractMethods(string code, Interfaces.SyntaxNode classNode)
{
- // 简化的方法匹配:查找方法签名
- var methodPattern = @"(public|private|protected)\s+(static\s+)?(\w+)\s+(\w+)\s*\(([^)]*)\)";
+ var methodPattern = @"(public|private|protected)\s+(static\s+)?(final\s+)?(synchronized\s+)?(?:(\w+(?:<[^>]+>?)(?:\[\])?)\s+)?(\w+)\s*\(([^)]*)\)(?:\s+throws\s+([\w,\s]+))?";
var methodMatches = System.Text.RegularExpressions.Regex.Matches(code, methodPattern);
+ var methodNames = new List();
foreach (System.Text.RegularExpressions.Match match in methodMatches)
{
- // 过滤掉类的声明
- if (match.Groups[3].Value == "class" || match.Groups[3].Value == "interface" || match.Groups[3].Value == "enum")
+ var methodName = match.Groups[6].Value;
+ if (methodName == "class" || methodName == "interface" || methodName == "enum" || methodName == "record")
continue;
+ methodNames.Add(methodName);
+
+ var returnType = string.IsNullOrEmpty(match.Groups[5].Value) ? "void" : match.Groups[5].Value;
var methodNode = new Interfaces.SyntaxNode
{
Type = SyntaxNodeType.Method,
@@ -213,27 +232,32 @@ public class JavaParser : BaseParser
{
["accessModifier"] = match.Groups[1].Value,
["isStatic"] = !string.IsNullOrEmpty(match.Groups[2].Value),
- ["returnType"] = match.Groups[3].Value,
- ["methodName"] = match.Groups[4].Value,
- ["parameters"] = match.Groups[5].Value
+ ["isFinal"] = !string.IsNullOrEmpty(match.Groups[3].Value),
+ ["isSynchronized"] = !string.IsNullOrEmpty(match.Groups[4].Value),
+ ["returnType"] = returnType,
+ ["methodName"] = methodName,
+ ["parameters"] = match.Groups[7].Value,
+ ["throws"] = match.Groups[8].Success ? match.Groups[8].Value : null
}
};
classNode.Children.Add(methodNode);
-
- // 提取参数
- ExtractParameters(match.Groups[5].Value, methodNode);
+ ExtractParameters(match.Groups[7].Value, methodNode);
}
+
+ classNode.Metadata["Methods"] = methodNames;
}
private void ExtractFields(string code, Interfaces.SyntaxNode classNode)
{
- // 简化的字段匹配
- var fieldPattern = @"(private|protected|public)\s+(static\s+)?(final\s+)?(\w+)\s+(\w+)\s*[;=]";
+ var fieldPattern = @"(private|protected|public)\s+(static\s+)?(final\s+)?(transient\s+)?(volatile\s+)?(\w+(?:<[^>]+>)?(?:\[\])?)\s+(\w+)\s*[;=]";
var fieldMatches = System.Text.RegularExpressions.Regex.Matches(code, fieldPattern);
+ var fieldNames = new List();
foreach (System.Text.RegularExpressions.Match match in fieldMatches)
{
+ fieldNames.Add(match.Groups[6].Value);
+
var fieldNode = new Interfaces.SyntaxNode
{
Type = SyntaxNodeType.Field,
@@ -241,26 +265,29 @@ public class JavaParser : BaseParser
Metadata = new Dictionary
{
["accessModifier"] = match.Groups[1].Value,
- ["type"] = match.Groups[4].Value,
- ["fieldName"] = match.Groups[5].Value
+ ["isStatic"] = !string.IsNullOrEmpty(match.Groups[2].Value),
+ ["isFinal"] = !string.IsNullOrEmpty(match.Groups[3].Value),
+ ["isTransient"] = !string.IsNullOrEmpty(match.Groups[4].Value),
+ ["isVolatile"] = !string.IsNullOrEmpty(match.Groups[5].Value),
+ ["type"] = match.Groups[5].Value,
+ ["fieldName"] = match.Groups[6].Value
}
};
classNode.Children.Add(fieldNode);
}
+
+ classNode.Metadata["Fields"] = fieldNames;
}
- private void ExtractConstructors(string code, Interfaces.SyntaxNode classNode)
+ private void ExtractConstructors(string code, Interfaces.SyntaxNode classNode, string className)
{
- var constructorPattern = @"(public|private|protected)?\s+(\w+)\s*\(([^)]*)\)\s*(throws\s+[\w,\s]+)?\s*(\{[^}]*\})";
+ var constructorPattern = @"(public|private|protected)?\s+(\w+)\s*\(([^)]*)\)(?:\s+throws\s+([\w,\s]+))?";
var constructorMatches = System.Text.RegularExpressions.Regex.Matches(code, constructorPattern);
foreach (System.Text.RegularExpressions.Match match in constructorMatches)
{
- var className = classNode.Metadata.ContainsKey("className") ? classNode.Metadata["className"]?.ToString() : null;
-
- // 确认是构造函数(名称与类名相同)
- if (className != null && match.Groups[2].Value == className)
+ if (match.Groups[2].Value == className)
{
var constructorNode = new Interfaces.SyntaxNode
{
@@ -271,24 +298,40 @@ public class JavaParser : BaseParser
["accessModifier"] = match.Groups[1].Value,
["constructorName"] = match.Groups[2].Value,
["parameters"] = match.Groups[3].Value,
- ["throws"] = string.IsNullOrEmpty(match.Groups[4].Value) ? null : match.Groups[4].Value
+ ["throws"] = match.Groups[4].Success ? match.Groups[4].Value : null
}
};
classNode.Children.Add(constructorNode);
-
- // 提取参数
ExtractParameters(match.Groups[3].Value, constructorNode);
}
}
}
+ private void ExtractAnnotations(string code, Interfaces.SyntaxNode classNode)
+ {
+ var annotationPattern = @"@(\w+)(?:\(([^)]*)\))?";
+ var annotationMatches = System.Text.RegularExpressions.Regex.Matches(code, annotationPattern);
+
+ var annotations = new List>();
+ foreach (System.Text.RegularExpressions.Match match in annotationMatches)
+ {
+ annotations.Add(new Dictionary
+ {
+ ["name"] = match.Groups[1].Value,
+ ["parameters"] = match.Groups[2].Success ? match.Groups[2].Value : null
+ });
+ }
+
+ classNode.Metadata["Annotations"] = annotations;
+ }
+
private void ExtractParameters(string parametersText, Interfaces.SyntaxNode parentNode)
{
if (string.IsNullOrWhiteSpace(parametersText))
return;
- var paramPattern = @"(\w+(?:<[^>]+>)?)\s+(\w+)";
+ var paramPattern = @"(?:@(\w+)(?:\([^)]*\)))?\s*(final\s+)?(\w+(?:<[^>]+>)?(?:\[\])?)\s+(\w+)";
var paramMatches = System.Text.RegularExpressions.Regex.Matches(parametersText, paramPattern);
foreach (System.Text.RegularExpressions.Match match in paramMatches)
@@ -299,8 +342,10 @@ public class JavaParser : BaseParser
Text = match.Value,
Metadata = new Dictionary
{
- ["type"] = match.Groups[1].Value,
- ["name"] = match.Groups[2].Value
+ ["annotation"] = match.Groups[1].Success ? match.Groups[1].Value : null,
+ ["isFinal"] = !string.IsNullOrEmpty(match.Groups[2].Value),
+ ["type"] = match.Groups[3].Value,
+ ["name"] = match.Groups[4].Value
}
};
@@ -313,12 +358,12 @@ public class JavaParser : BaseParser
var lines = sourceCode.Split('\n');
bool inMultiLineComment = false;
var multiLineComment = new StringBuilder();
+ var multiLineStart = 0;
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i];
- // 单行注释
var singleLineMatch = System.Text.RegularExpressions.Regex.Match(line, @"//\s*(.*)");
if (singleLineMatch.Success)
{
@@ -330,16 +375,15 @@ public class JavaParser : BaseParser
});
}
- // 多行注释开始
if (line.Contains("/*") && !line.Contains("*/"))
{
inMultiLineComment = true;
multiLineComment.AppendLine(line);
+ multiLineStart = i + 1;
continue;
}
- // 多行注释中
- if (inMultiLineComment && line.Contains("*/"))
+ if (inMultiLineComment)
{
multiLineComment.AppendLine(line);
if (line.Contains("*/"))
@@ -349,7 +393,7 @@ public class JavaParser : BaseParser
{
Text = multiLineComment.ToString().Trim(),
Type = CommentType.MultiLine,
- LineNumber = i - multiLineComment.ToString().Split('\n').Length + 1
+ LineNumber = multiLineStart
});
multiLineComment.Clear();
}
@@ -367,9 +411,8 @@ public class JavaParser : BaseParser
var content = match.Groups[1].Value.Trim();
var lineNumber = GetLineNumber(sourceCode, match.Index);
- // 查找相邻的元素名称
var afterDoc = sourceCode.Substring(match.Index + match.Length);
- var elementMatch = System.Text.RegularExpressions.Regex.Match(afterDoc, @"(class|interface|enum|method|constructor|field)\s+(\w+)");
+ var elementMatch = System.Text.RegularExpressions.Regex.Match(afterDoc, @"@(interface|@interface|class|enum|record)\s+(\w+)");
tree.Documentation.Add(new SyntaxDocumentation
{
@@ -380,6 +423,40 @@ public class JavaParser : BaseParser
}
}
+ private void ExtractAdvancedFeatures(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root)
+ {
+ // 检测 Lambda 表达式
+ var lambdaCount = System.Text.RegularExpressions.Regex.Matches(sourceCode, @"->").Count;
+ root.Metadata["LambdaCount"] = lambdaCount;
+
+ // 检测 Stream API 使用
+ var streamMethods = new[] { "stream()", "filter(", "map(", "flatMap(", "collect(", "reduce(", "forEach(" };
+ var streamUsage = streamMethods.Count(m => sourceCode.Contains(m));
+ root.Metadata["StreamUsage"] = streamUsage;
+
+ // 检测 Optional 使用
+ var optionalCount = System.Text.RegularExpressions.Regex.Matches(sourceCode, @"Optional(?:<[^>]+>)?").Count;
+ root.Metadata["OptionalUsage"] = optionalCount;
+
+ // 检测泛型使用
+ var genericPattern = @"<([^>]+)>";
+ var genericMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, genericPattern);
+ var typeParameters = genericMatches.Cast()
+ .Select(m => m.Groups[1].Value)
+ .Distinct()
+ .ToList();
+ root.Metadata["TypeParameters"] = typeParameters;
+
+ // 检测注解使用
+ var annotationPattern = @"@(\w+)";
+ var annotationMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, annotationPattern);
+ var annotations = annotationMatches.Cast()
+ .Select(m => m.Groups[1].Value)
+ .Distinct()
+ .ToList();
+ root.Metadata["Annotations"] = annotations;
+ }
+
private int GetLineNumber(string sourceCode, int index)
{
return sourceCode.Substring(0, index).Count(c => c == '\n') + 1;
diff --git a/CodePlay.Core/Services/TodoGenerator.cs b/CodePlay.Core/Services/TodoGenerator.cs
index 82ce44f..3d794bf 100644
--- a/CodePlay.Core/Services/TodoGenerator.cs
+++ b/CodePlay.Core/Services/TodoGenerator.cs
@@ -5,19 +5,102 @@ namespace CodePlay.Core.Services;
public class TodoGenerator
{
+ private static readonly List 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 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 GenerateTodos(string sourceCode, LanguageType sourceLanguage, LanguageType targetLanguage)
{
var todos = new List();
- return todos;
+ 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;
+ 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 ConversionConversionSuggestion
+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; }