Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85fdcff103 | |||
| 1e15e90d32 | |||
| aae6087f90 | |||
| 0955bb39e3 | |||
| ccc7f1bc8c |
@@ -105,31 +105,54 @@ public abstract class TypeDeclaration : JavaNode
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Modifiers Modifiers { get; set; }
|
||||
public List<MemberDeclaration> Members { get; set; }
|
||||
public List<Annotation> Annotations { get; set; }
|
||||
public List<TypeParameter> TypeParameters { get; set; }
|
||||
public JavaDoc? JavaDoc { get; set; }
|
||||
|
||||
// Gets the body/members of this type declaration
|
||||
public abstract IEnumerable<JavaNode> Body { get; }
|
||||
}
|
||||
|
||||
public class ClassDeclaration : TypeDeclaration
|
||||
{
|
||||
public TypeNode? Superclass { get; set; }
|
||||
public List<TypeNode> Interfaces { get; set; }
|
||||
public List<TypeParameter> TypeParameters { get; set; }
|
||||
public TypeReference? SuperClass { get; set; }
|
||||
public List<TypeReference> Interfaces { get; set; }
|
||||
public List<MemberDeclaration> Members { get; set; }
|
||||
public List<TypeDeclaration> NestedTypes { get; set; }
|
||||
public bool IsRecord { get; set; }
|
||||
|
||||
// Body includes both Members and NestedTypes
|
||||
public override IEnumerable<JavaNode> Body => Members.Concat(NestedTypes);
|
||||
}
|
||||
|
||||
public class InterfaceDeclaration : TypeDeclaration
|
||||
{
|
||||
public List<TypeNode> ExtendedInterfaces { get; set; }
|
||||
public List<TypeParameter> TypeParameters { get; set; }
|
||||
public List<TypeReference> ExtendedInterfaces { get; set; }
|
||||
public List<MemberDeclaration> Members { get; set; }
|
||||
public List<TypeDeclaration> NestedTypes { get; set; }
|
||||
|
||||
// Body includes both Members and NestedTypes
|
||||
public override IEnumerable<JavaNode> Body => Members.Concat(NestedTypes);
|
||||
}
|
||||
|
||||
public class EnumDeclaration : TypeDeclaration
|
||||
{
|
||||
public List<TypeReference> Interfaces { get; set; }
|
||||
public List<EnumConstant> Constants { get; set; }
|
||||
public List<TypeNode> Interfaces { get; set; }
|
||||
public List<MemberDeclaration> Members { get; set; }
|
||||
public List<TypeDeclaration> NestedTypes { get; set; }
|
||||
|
||||
// Body includes Constants, Members and NestedTypes
|
||||
public override IEnumerable<JavaNode> Body => Constants.Concat(Members).Concat(NestedTypes);
|
||||
}
|
||||
|
||||
public class AnnotationDeclaration : TypeDeclaration
|
||||
{
|
||||
public List<AnnotationMember> Members { get; set; }
|
||||
public List<TypeDeclaration> NestedTypes { get; set; }
|
||||
|
||||
// Body includes both Members and NestedTypes
|
||||
public override IEnumerable<JavaNode> Body => Members.Concat(NestedTypes);
|
||||
}
|
||||
|
||||
public class RecordDeclaration : TypeDeclaration
|
||||
@@ -720,6 +743,18 @@ var mainMethod = AstQuery.FirstOrDefault<MethodDeclaration>(compilationUnit,
|
||||
var containingClass = AstQuery.GetAncestors(method, compilationUnit)
|
||||
.OfType<ClassDeclaration>()
|
||||
.FirstOrDefault();
|
||||
|
||||
// Find all nested types in a class
|
||||
var outerClass = compilationUnit.Types.OfType<ClassDeclaration>().First();
|
||||
var allNestedTypes = outerClass.NestedTypes;
|
||||
|
||||
// Find nested interfaces specifically
|
||||
var nestedInterfaces = outerClass.NestedTypes
|
||||
.OfType<InterfaceDeclaration>();
|
||||
|
||||
// Recursively find all nested types (including deeply nested)
|
||||
var allNested = AstQuery.FindAll<TypeDeclaration>(outerClass)
|
||||
.Where(t => t != outerClass);
|
||||
```
|
||||
|
||||
## AST Transformation API
|
||||
|
||||
@@ -196,12 +196,12 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var typeParameters = BuildTypeParameters(context.typeParameters());
|
||||
var superClass = context.superclass() != null ? BuildTypeReference(context.superclass().classType()) : null;
|
||||
var interfaces = BuildInterfaces(context.superinterfaces());
|
||||
var members = BuildClassMembers(context.classBody());
|
||||
var bodyResult = BuildClassBody(context.classBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new ClassDeclaration(
|
||||
location, name, modifiers, annotations, typeParameters,
|
||||
superClass, interfaces, members, new List<TypeDeclaration>(), javaDoc, false
|
||||
superClass, interfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -213,12 +213,12 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var name = context.identifier().GetText();
|
||||
var typeParameters = BuildTypeParameters(context.typeParameters());
|
||||
var extendedInterfaces = BuildExtendedInterfaces(context.extendsInterfaces());
|
||||
var members = BuildInterfaceMembers(context.interfaceBody());
|
||||
var bodyResult = BuildInterfaceBody(context.interfaceBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new InterfaceDeclaration(
|
||||
location, name, modifiers, annotations, typeParameters,
|
||||
extendedInterfaces, members, new List<TypeDeclaration>(), javaDoc
|
||||
extendedInterfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc
|
||||
);
|
||||
}
|
||||
|
||||
@@ -231,12 +231,15 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var interfaces = BuildInterfaces(context.superinterfaces());
|
||||
var enumBody = context.enumBody();
|
||||
var constants = BuildEnumConstants(enumBody.enumConstantList());
|
||||
var members = BuildEnumMembers(enumBody.enumBodyDeclarations());
|
||||
var bodyResult = BuildEnumBody(enumBody.enumBodyDeclarations());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
return new EnumDeclaration(
|
||||
location, name, modifiers, annotations,
|
||||
interfaces, constants, members, new List<TypeDeclaration>(), javaDoc
|
||||
interfaces, constants,
|
||||
bodyResult?.Members ?? new List<MemberDeclaration>(),
|
||||
bodyResult?.NestedTypes ?? new List<TypeDeclaration>(),
|
||||
javaDoc
|
||||
);
|
||||
}
|
||||
|
||||
@@ -249,6 +252,7 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var members = BuildAnnotationMembers(context.annotationTypeBody());
|
||||
var javaDoc = ExtractJavaDoc(context);
|
||||
|
||||
// Annotations don't support nested types in Java
|
||||
return new AnnotationDeclaration(
|
||||
location, name, modifiers, annotations, members, new List<TypeDeclaration>(), javaDoc
|
||||
);
|
||||
@@ -293,11 +297,24 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var annotations = new List<Annotation>();
|
||||
foreach (var context in contexts)
|
||||
{
|
||||
// Check if this is directly an annotation context
|
||||
if (context is Java9Parser.AnnotationContext annotationContext)
|
||||
{
|
||||
var annotation = BuildAnnotation(annotationContext);
|
||||
if (annotation != null) annotations.Add(annotation);
|
||||
}
|
||||
// Check if this is a modifier that contains an annotation
|
||||
else if (context is ParserRuleContext ruleContext && ruleContext.ChildCount > 0)
|
||||
{
|
||||
// The first child of a modifier rule that represents an annotation
|
||||
// will be an AnnotationContext
|
||||
var firstChild = ruleContext.GetChild(0);
|
||||
if (firstChild is Java9Parser.AnnotationContext childAnnotation)
|
||||
{
|
||||
var annotation = BuildAnnotation(childAnnotation);
|
||||
if (annotation != null) annotations.Add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
@@ -308,25 +325,37 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
TypeReference? type = null;
|
||||
var arguments = new List<AnnotationArgument>();
|
||||
|
||||
|
||||
// Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
|
||||
if (context.normalAnnotation() != null)
|
||||
{
|
||||
var normalAnn = context.normalAnnotation();
|
||||
type = BuildTypeReference(normalAnn.typeName());
|
||||
if (type == null) return null;
|
||||
// Don't return early - try to build the type from the name
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = normalAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(normalAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
|
||||
if (normalAnn.elementValuePairList() != null)
|
||||
{
|
||||
foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
|
||||
{
|
||||
var name = pair.identifier().GetText();
|
||||
var value = BuildExpression(pair.elementValue());
|
||||
if (value != null)
|
||||
var value = BuildElementValue(pair.elementValue());
|
||||
|
||||
// Debug - always add the argument even if value is null
|
||||
// If value is null, create a string literal as fallback
|
||||
if (value == null)
|
||||
{
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
GetSourceRange(pair), name, value
|
||||
));
|
||||
var elementText = pair.elementValue().GetText();
|
||||
value = new LiteralExpression(GetSourceRange(pair.elementValue()), elementText, LiteralKind.String);
|
||||
}
|
||||
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
GetSourceRange(pair), name, value
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,30 +363,89 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
{
|
||||
var markerAnn = context.markerAnnotation();
|
||||
type = BuildTypeReference(markerAnn.typeName());
|
||||
if (type == null) return null;
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = markerAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(markerAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
// Marker annotations have no arguments
|
||||
}
|
||||
else if (context.singleElementAnnotation() != null)
|
||||
{
|
||||
var singleAnn = context.singleElementAnnotation();
|
||||
type = BuildTypeReference(singleAnn.typeName());
|
||||
if (type == null) return null;
|
||||
if (type == null)
|
||||
{
|
||||
var typeName = singleAnn.typeName().GetText();
|
||||
type = new ClassOrInterfaceType(GetSourceRange(singleAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
||||
}
|
||||
|
||||
if (singleAnn.elementValue() != null)
|
||||
{
|
||||
var value = BuildExpression(singleAnn.elementValue());
|
||||
if (value != null)
|
||||
var value = BuildElementValue(singleAnn.elementValue());
|
||||
|
||||
// Fallback if BuildElementValue returns null
|
||||
if (value == null)
|
||||
{
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
location, "value", value
|
||||
));
|
||||
var elementText = singleAnn.elementValue().GetText();
|
||||
value = new LiteralExpression(GetSourceRange(singleAnn.elementValue()), elementText, LiteralKind.String);
|
||||
}
|
||||
|
||||
arguments.Add(new AnnotationValueArgument(
|
||||
location, "value", value
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return type != null ? new Annotation(location, type, arguments) : null;
|
||||
}
|
||||
|
||||
private Expression? BuildElementValue(Java9Parser.ElementValueContext context)
|
||||
{
|
||||
if (context.conditionalExpression() != null)
|
||||
{
|
||||
var expr = BuildExpression(context.conditionalExpression());
|
||||
// If BuildExpression returns null, try to parse it as a string literal
|
||||
if (expr == null)
|
||||
{
|
||||
var text = context.conditionalExpression().GetText();
|
||||
if (text.StartsWith('"') && text.EndsWith('"'))
|
||||
{
|
||||
// Remove quotes and create a string literal
|
||||
var value = text.Substring(1, text.Length - 2);
|
||||
expr = new LiteralExpression(GetSourceRange(context), value, LiteralKind.String);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
else if (context.annotation() != null)
|
||||
{
|
||||
var annotation = BuildAnnotation(context.annotation());
|
||||
if (annotation != null)
|
||||
{
|
||||
return new AnnotationExpression(GetSourceRange(context), annotation);
|
||||
}
|
||||
}
|
||||
else if (context.elementValueArrayInitializer() != null)
|
||||
{
|
||||
var arrayInit = context.elementValueArrayInitializer();
|
||||
var elements = new List<Expression>();
|
||||
|
||||
if (arrayInit.elementValueList() != null)
|
||||
{
|
||||
foreach (var elementValue in arrayInit.elementValueList().elementValue())
|
||||
{
|
||||
var element = BuildElementValue(elementValue);
|
||||
if (element != null) elements.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayInitializer(GetSourceRange(arrayInit), elements);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<TypeParameter> BuildTypeParameters(Java9Parser.TypeParametersContext? context)
|
||||
{
|
||||
if (context == null) return new List<TypeParameter>();
|
||||
@@ -410,8 +498,8 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
Java9Parser.ArrayTypeContext array => BuildArrayType(array),
|
||||
Java9Parser.TypeVariableContext typeVar => BuildTypeVariable(typeVar),
|
||||
Java9Parser.ClassTypeContext classType => BuildClassType(classType),
|
||||
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
||||
Java9Parser.TypeNameContext typeName => BuildTypeName(typeName),
|
||||
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -667,6 +755,54 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult BuildClassBody(Java9Parser.ClassBodyContext context)
|
||||
{
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.classBodyDeclaration())
|
||||
{
|
||||
if (declaration.classMemberDeclaration() != null)
|
||||
{
|
||||
var classMemberContext = declaration.classMemberDeclaration();
|
||||
|
||||
// Check if it's a nested type declaration
|
||||
if (classMemberContext.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (classMemberContext.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a regular member (field or method)
|
||||
var member = BuildClassMember(classMemberContext);
|
||||
if (member != null) result.Members.Add(member);
|
||||
}
|
||||
}
|
||||
else if (declaration.instanceInitializer() != null)
|
||||
{
|
||||
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.staticInitializer() != null)
|
||||
{
|
||||
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.constructorDeclaration() != null)
|
||||
{
|
||||
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
||||
if (constructor != null) result.Members.Add(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private MemberDeclaration? BuildClassMember(Java9Parser.ClassMemberDeclarationContext context)
|
||||
{
|
||||
if (context.fieldDeclaration() != null)
|
||||
@@ -677,15 +813,8 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
{
|
||||
return BuildMethodDeclaration(context.methodDeclaration());
|
||||
}
|
||||
else if (context.classDeclaration() != null)
|
||||
{
|
||||
return Visit(context.classDeclaration()) as MemberDeclaration;
|
||||
}
|
||||
else if (context.interfaceDeclaration() != null)
|
||||
{
|
||||
return Visit(context.interfaceDeclaration()) as MemberDeclaration;
|
||||
}
|
||||
|
||||
// Nested types are now handled in BuildClassBody
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -935,6 +1064,13 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
|
||||
private Parameter? BuildLastParameter(Java9Parser.LastFormalParameterContext context)
|
||||
{
|
||||
// Check if this is just a regular parameter (not varargs)
|
||||
if (context.formalParameter() != null)
|
||||
{
|
||||
return BuildParameter(context.formalParameter());
|
||||
}
|
||||
|
||||
// Otherwise, it's a varargs parameter
|
||||
var location = GetSourceRange(context);
|
||||
var modifiers = BuildModifiers(context.variableModifier());
|
||||
var annotations = BuildAnnotations(context.variableModifier());
|
||||
@@ -944,7 +1080,7 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
var declaratorId = context.variableDeclaratorId();
|
||||
var name = declaratorId.identifier().GetText();
|
||||
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
||||
var isVarArgs = context.GetChild(context.ChildCount - 2)?.GetText() == "...";
|
||||
var isVarArgs = true; // This branch is only for varargs
|
||||
|
||||
return new Parameter(location, type, name, isVarArgs, isFinal, annotations);
|
||||
}
|
||||
@@ -1040,6 +1176,37 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult BuildInterfaceBody(Java9Parser.InterfaceBodyContext context)
|
||||
{
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.interfaceMemberDeclaration())
|
||||
{
|
||||
if (declaration.constantDeclaration() != null)
|
||||
{
|
||||
var constant = BuildConstantDeclaration(declaration.constantDeclaration());
|
||||
if (constant != null) result.Members.Add(constant);
|
||||
}
|
||||
else if (declaration.interfaceMethodDeclaration() != null)
|
||||
{
|
||||
var method = BuildInterfaceMethodDeclaration(declaration.interfaceMethodDeclaration());
|
||||
if (method != null) result.Members.Add(method);
|
||||
}
|
||||
else if (declaration.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(declaration.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (declaration.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(declaration.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private FieldDeclaration? BuildConstantDeclaration(Java9Parser.ConstantDeclarationContext context)
|
||||
{
|
||||
var location = GetSourceRange(context);
|
||||
@@ -1172,6 +1339,56 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
return members;
|
||||
}
|
||||
|
||||
private ClassBodyResult? BuildEnumBody(Java9Parser.EnumBodyDeclarationsContext? context)
|
||||
{
|
||||
if (context == null) return null;
|
||||
|
||||
var result = new ClassBodyResult();
|
||||
|
||||
foreach (var declaration in context.classBodyDeclaration())
|
||||
{
|
||||
if (declaration.classMemberDeclaration() != null)
|
||||
{
|
||||
var classMemberContext = declaration.classMemberDeclaration();
|
||||
|
||||
// Check if it's a nested type declaration
|
||||
if (classMemberContext.classDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else if (classMemberContext.interfaceDeclaration() != null)
|
||||
{
|
||||
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
||||
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a regular member (field or method)
|
||||
var member = BuildClassMember(classMemberContext);
|
||||
if (member != null) result.Members.Add(member);
|
||||
}
|
||||
}
|
||||
else if (declaration.instanceInitializer() != null)
|
||||
{
|
||||
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.staticInitializer() != null)
|
||||
{
|
||||
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
||||
if (initializer != null) result.Members.Add(initializer);
|
||||
}
|
||||
else if (declaration.constructorDeclaration() != null)
|
||||
{
|
||||
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
||||
if (constructor != null) result.Members.Add(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<AnnotationMember> BuildAnnotationMembers(Java9Parser.AnnotationTypeBodyContext context)
|
||||
{
|
||||
var members = new List<AnnotationMember>();
|
||||
@@ -1199,7 +1416,7 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
|
||||
if (context.defaultValue() != null)
|
||||
{
|
||||
defaultValue = BuildExpression(context.defaultValue().elementValue());
|
||||
defaultValue = BuildElementValue(context.defaultValue().elementValue());
|
||||
}
|
||||
|
||||
return new AnnotationMember(location, name, type, defaultValue);
|
||||
@@ -2464,46 +2681,6 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private Expression? BuildElementValue(Java9Parser.ElementValueContext context)
|
||||
{
|
||||
if (context.conditionalExpression() != null)
|
||||
{
|
||||
return BuildConditionalExpression(context.conditionalExpression());
|
||||
}
|
||||
else if (context.elementValueArrayInitializer() != null)
|
||||
{
|
||||
return BuildElementValueArrayInitializer(context.elementValueArrayInitializer());
|
||||
}
|
||||
else if (context.annotation() != null)
|
||||
{
|
||||
// Annotation as expression - wrap it
|
||||
var annotation = BuildAnnotation(context.annotation());
|
||||
if (annotation != null)
|
||||
{
|
||||
// Create a special expression to hold the annotation
|
||||
return new IdentifierExpression(annotation.Location, "@" + annotation.Type.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ArrayInitializer? BuildElementValueArrayInitializer(Java9Parser.ElementValueArrayInitializerContext context)
|
||||
{
|
||||
var location = GetSourceRange(context);
|
||||
var elements = new List<Expression>();
|
||||
|
||||
if (context.elementValueList() != null)
|
||||
{
|
||||
foreach (var value in context.elementValueList().elementValue())
|
||||
{
|
||||
var expr = BuildElementValue(value);
|
||||
if (expr != null) elements.Add(expr);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayInitializer(location, elements);
|
||||
}
|
||||
|
||||
// Statement building methods
|
||||
|
||||
@@ -3464,5 +3641,12 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
||||
|
||||
return new JavaDoc(range, content, tags);
|
||||
}
|
||||
|
||||
// Helper classes for building class bodies with both members and nested types
|
||||
private class ClassBodyResult
|
||||
{
|
||||
public List<MemberDeclaration> Members { get; set; } = new List<MemberDeclaration>();
|
||||
public List<TypeDeclaration> NestedTypes { get; set; } = new List<TypeDeclaration>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,6 +400,23 @@ namespace MarketAlly.IronJava.Core.AST.Nodes
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitArrayInitializer(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an annotation used as an expression (in annotation element values).
|
||||
/// </summary>
|
||||
public class AnnotationExpression : Expression
|
||||
{
|
||||
public Annotation Annotation { get; }
|
||||
|
||||
public AnnotationExpression(SourceRange location, Annotation annotation) : base(location)
|
||||
{
|
||||
Annotation = annotation;
|
||||
AddChild(annotation);
|
||||
}
|
||||
|
||||
public override T Accept<T>(IJavaVisitor<T> visitor) => visitor.VisitAnnotationExpression(this);
|
||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitAnnotationExpression(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a lambda expression.
|
||||
/// </summary>
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
void VisitNewExpression(NewExpression node);
|
||||
void VisitNewArrayExpression(NewArrayExpression node);
|
||||
void VisitArrayInitializer(ArrayInitializer node);
|
||||
void VisitAnnotationExpression(AnnotationExpression node);
|
||||
void VisitLambdaExpression(LambdaExpression node);
|
||||
void VisitLambdaParameter(LambdaParameter node);
|
||||
void VisitMethodReferenceExpression(MethodReferenceExpression node);
|
||||
@@ -135,6 +136,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
T VisitNewExpression(NewExpression node);
|
||||
T VisitNewArrayExpression(NewArrayExpression node);
|
||||
T VisitArrayInitializer(ArrayInitializer node);
|
||||
T VisitAnnotationExpression(AnnotationExpression node);
|
||||
T VisitLambdaExpression(LambdaExpression node);
|
||||
T VisitLambdaParameter(LambdaParameter node);
|
||||
T VisitMethodReferenceExpression(MethodReferenceExpression node);
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
public virtual void VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitArrayInitializer(ArrayInitializer node) => DefaultVisit(node);
|
||||
public virtual void VisitAnnotationExpression(AnnotationExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||
public virtual void VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||
public virtual void VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
||||
@@ -133,6 +134,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
||||
public virtual T VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitArrayInitializer(ArrayInitializer node) => DefaultVisit(node);
|
||||
public virtual T VisitAnnotationExpression(AnnotationExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||
public virtual T VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||
public virtual T VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<!-- NuGet Package Metadata -->
|
||||
<PackageId>IronJava</PackageId>
|
||||
<Version>2.0.0</Version>
|
||||
<Version>2.1.2</Version>
|
||||
<Authors>David H Friedel Jr</Authors>
|
||||
<Company>MarketAlly</Company>
|
||||
<Title>IronJava</Title>
|
||||
|
||||
@@ -416,6 +416,22 @@ namespace MarketAlly.IronJava.Core.Serialization
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationValueArgument(AnnotationValueArgument node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["name"] = node.Name;
|
||||
result["value"] = node.Value.Accept(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationArrayArgument(AnnotationArrayArgument node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["name"] = node.Name;
|
||||
result["values"] = node.Values.Select(v => v.Accept(this)).ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitJavaDoc(JavaDoc node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
@@ -561,6 +577,13 @@ namespace MarketAlly.IronJava.Core.Serialization
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitAnnotationExpression(AnnotationExpression node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
result["annotation"] = node.Annotation.Accept(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Dictionary<string, object?> VisitMethodReferenceExpression(MethodReferenceExpression node)
|
||||
{
|
||||
var result = CreateBaseNode(node);
|
||||
@@ -747,6 +770,9 @@ namespace MarketAlly.IronJava.Core.Serialization
|
||||
"InstanceOfExpression" => DeserializeInstanceOfExpression(element, location),
|
||||
"NewArrayExpression" => DeserializeNewArrayExpression(element, location),
|
||||
"ArrayInitializer" => DeserializeArrayInitializer(element, location),
|
||||
"AnnotationExpression" => DeserializeAnnotationExpression(element, location),
|
||||
"AnnotationValueArgument" => DeserializeAnnotationValueArgument(element, location),
|
||||
"AnnotationArrayArgument" => DeserializeAnnotationArrayArgument(element, location),
|
||||
"MethodReferenceExpression" => DeserializeMethodReferenceExpression(element, location),
|
||||
"ClassLiteralExpression" => DeserializeClassLiteralExpression(element, location),
|
||||
"LocalVariableStatement" => DeserializeLocalVariableStatement(element, location),
|
||||
@@ -1282,6 +1308,30 @@ namespace MarketAlly.IronJava.Core.Serialization
|
||||
return new ArrayInitializer(location, elements);
|
||||
}
|
||||
|
||||
private AnnotationExpression DeserializeAnnotationExpression(JsonElement element, SourceRange location)
|
||||
{
|
||||
var annotation = Deserialize(element.GetProperty("annotation")) as Annotation ?? throw new JsonException("annotation is not Annotation");
|
||||
return new AnnotationExpression(location, annotation);
|
||||
}
|
||||
|
||||
private AnnotationValueArgument DeserializeAnnotationValueArgument(JsonElement element, SourceRange location)
|
||||
{
|
||||
var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null
|
||||
? nameEl.GetString()
|
||||
: null;
|
||||
var value = Deserialize(element.GetProperty("value")) as Expression ?? throw new JsonException("value is not Expression");
|
||||
return new AnnotationValueArgument(location, name, value);
|
||||
}
|
||||
|
||||
private AnnotationArrayArgument DeserializeAnnotationArrayArgument(JsonElement element, SourceRange location)
|
||||
{
|
||||
var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null
|
||||
? nameEl.GetString()
|
||||
: null;
|
||||
var values = DeserializeList<Expression>(element.GetProperty("values"));
|
||||
return new AnnotationArrayArgument(location, name, values);
|
||||
}
|
||||
|
||||
private MethodReferenceExpression DeserializeMethodReferenceExpression(JsonElement element, SourceRange location)
|
||||
{
|
||||
var target = Deserialize(element.GetProperty("target")) as Expression ?? throw new JsonException("target is not Expression");
|
||||
|
||||
215
IronJava.Tests/AnnotationParsingTests.cs
Normal file
215
IronJava.Tests/AnnotationParsingTests.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using System.Linq;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
using MarketAlly.IronJava.Core.AST.Query;
|
||||
using Xunit;
|
||||
|
||||
namespace MarketAlly.IronJava.Tests
|
||||
{
|
||||
public class AnnotationParsingTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestClassAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
@Entity
|
||||
@Table(name = ""users"")
|
||||
public class User {
|
||||
private String name;
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var userClass = result.Ast.Types.OfType<ClassDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(userClass);
|
||||
Assert.Equal("User", userClass.Name);
|
||||
|
||||
// Check annotations
|
||||
Assert.Equal(2, userClass.Annotations.Count);
|
||||
|
||||
var entityAnnotation = userClass.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Entity");
|
||||
Assert.NotNull(entityAnnotation);
|
||||
Assert.Empty(entityAnnotation.Arguments);
|
||||
|
||||
var tableAnnotation = userClass.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Table");
|
||||
Assert.NotNull(tableAnnotation);
|
||||
Assert.Single(tableAnnotation.Arguments);
|
||||
|
||||
var nameArg = tableAnnotation.Arguments[0] as AnnotationValueArgument;
|
||||
Assert.NotNull(nameArg);
|
||||
Assert.Equal("name", nameArg.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestMethodAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class UserService {
|
||||
@GetMapping(""/users/{id}"")
|
||||
@ResponseBody
|
||||
public User getUser(@PathVariable Long id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var method = AstQuery.FindFirst<MethodDeclaration>(result.Ast);
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal("getUser", method.Name);
|
||||
|
||||
// Check method annotations
|
||||
Assert.Equal(2, method.Annotations.Count);
|
||||
|
||||
var getMappingAnnotation = method.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "GetMapping");
|
||||
Assert.NotNull(getMappingAnnotation);
|
||||
Assert.Single(getMappingAnnotation.Arguments);
|
||||
|
||||
var responseBodyAnnotation = method.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "ResponseBody");
|
||||
Assert.NotNull(responseBodyAnnotation);
|
||||
Assert.Empty(responseBodyAnnotation.Arguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestFieldAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var fields = AstQuery.FindAll<FieldDeclaration>(result.Ast).ToList();
|
||||
Assert.Equal(2, fields.Count);
|
||||
|
||||
// Check id field annotations
|
||||
var idField = fields.FirstOrDefault(f => f.Variables[0].Name == "id");
|
||||
Assert.NotNull(idField);
|
||||
Assert.Equal(2, idField.Annotations.Count);
|
||||
|
||||
var idAnnotation = idField.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Id");
|
||||
Assert.NotNull(idAnnotation);
|
||||
|
||||
var generatedValueAnnotation = idField.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "GeneratedValue");
|
||||
Assert.NotNull(generatedValueAnnotation);
|
||||
Assert.Single(generatedValueAnnotation.Arguments);
|
||||
|
||||
// Check name field annotations
|
||||
var nameField = fields.FirstOrDefault(f => f.Variables[0].Name == "name");
|
||||
Assert.NotNull(nameField);
|
||||
Assert.Single(nameField.Annotations);
|
||||
|
||||
var columnAnnotation = nameField.Annotations[0];
|
||||
Assert.Equal("Column", ((ClassOrInterfaceType)columnAnnotation.Type).Name);
|
||||
Assert.Equal(2, columnAnnotation.Arguments.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestParameterAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class UserController {
|
||||
public void updateUser(@RequestBody User user, @PathVariable Long id) {
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var method = AstQuery.FindFirst<MethodDeclaration>(result.Ast);
|
||||
Assert.NotNull(method);
|
||||
Assert.Equal(2, method.Parameters.Count);
|
||||
|
||||
// Check first parameter annotations
|
||||
var userParam = method.Parameters[0];
|
||||
Assert.Equal("user", userParam.Name);
|
||||
Assert.Single(userParam.Annotations);
|
||||
Assert.Equal("RequestBody", ((ClassOrInterfaceType)userParam.Annotations[0].Type).Name);
|
||||
|
||||
// Check second parameter annotations
|
||||
var idParam = method.Parameters[1];
|
||||
Assert.Equal("id", idParam.Name);
|
||||
Assert.Single(idParam.Annotations);
|
||||
Assert.Equal("PathVariable", ((ClassOrInterfaceType)idParam.Annotations[0].Type).Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestNestedAnnotations()
|
||||
{
|
||||
var javaCode = @"
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MyAnnotation {
|
||||
String value() default ""default"";
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var annotationDecl = result.Ast.Types.OfType<AnnotationDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(annotationDecl);
|
||||
Assert.Equal("MyAnnotation", annotationDecl.Name);
|
||||
|
||||
// Check meta-annotations
|
||||
Assert.Equal(2, annotationDecl.Annotations.Count);
|
||||
|
||||
var targetAnnotation = annotationDecl.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Target");
|
||||
Assert.NotNull(targetAnnotation);
|
||||
Assert.Single(targetAnnotation.Arguments);
|
||||
|
||||
var retentionAnnotation = annotationDecl.Annotations.FirstOrDefault(a => ((ClassOrInterfaceType)a.Type).Name == "Retention");
|
||||
Assert.NotNull(retentionAnnotation);
|
||||
Assert.Single(retentionAnnotation.Arguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestAnnotationArrayValues()
|
||||
{
|
||||
var javaCode = @"
|
||||
@SuppressWarnings({""unchecked"", ""rawtypes""})
|
||||
public class Test {
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
Assert.True(result.Success);
|
||||
Assert.NotNull(result.Ast);
|
||||
|
||||
var testClass = result.Ast.Types.OfType<ClassDeclaration>().FirstOrDefault();
|
||||
Assert.NotNull(testClass);
|
||||
Assert.Single(testClass.Annotations);
|
||||
|
||||
var suppressWarningsAnnotation = testClass.Annotations[0];
|
||||
Assert.Equal("SuppressWarnings", ((ClassOrInterfaceType)suppressWarningsAnnotation.Type).Name);
|
||||
Assert.Single(suppressWarningsAnnotation.Arguments);
|
||||
|
||||
var valueArg = suppressWarningsAnnotation.Arguments[0] as AnnotationValueArgument;
|
||||
Assert.NotNull(valueArg);
|
||||
Assert.Equal("value", valueArg.Name);
|
||||
|
||||
// The value should be an ArrayInitializer expression
|
||||
var arrayInit = valueArg.Value as ArrayInitializer;
|
||||
Assert.NotNull(arrayInit);
|
||||
Assert.Equal(2, arrayInit.Elements.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
README.md
15
README.md
@@ -82,9 +82,17 @@ CompilationUnit
|
||||
├── ImportDeclaration[]
|
||||
└── TypeDeclaration[]
|
||||
├── ClassDeclaration
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
├── InterfaceDeclaration
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
├── EnumDeclaration
|
||||
│ ├── Constants[]
|
||||
│ ├── Members[]
|
||||
│ └── NestedTypes[]
|
||||
└── AnnotationDeclaration
|
||||
└── Members[]
|
||||
```
|
||||
|
||||
### Visitor Pattern
|
||||
@@ -152,6 +160,13 @@ var serializableClasses = ast
|
||||
var getters = ast
|
||||
.FindAll<MethodDeclaration>()
|
||||
.Where(m => m.IsGetter());
|
||||
|
||||
// Access nested types
|
||||
var outerClass = ast.Types.OfType<ClassDeclaration>().First();
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($"Nested: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
}
|
||||
```
|
||||
|
||||
### JSON Serialization
|
||||
|
||||
58
TestNestedTypes.cs
Normal file
58
TestNestedTypes.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using MarketAlly.IronJava.Core;
|
||||
using MarketAlly.IronJava.Core.AST.Nodes;
|
||||
|
||||
class TestNestedTypes
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
var javaCode = @"
|
||||
public class OuterClass {
|
||||
private int outerField;
|
||||
|
||||
public class InnerClass {
|
||||
private String innerField;
|
||||
|
||||
public void innerMethod() {
|
||||
System.out.println(innerField);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StaticNestedClass {
|
||||
private static int staticField;
|
||||
}
|
||||
|
||||
public interface NestedInterface {
|
||||
void doSomething();
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("Parse successful!");
|
||||
var outerClass = result.Ast.Types[0] as ClassDeclaration;
|
||||
if (outerClass != null)
|
||||
{
|
||||
Console.WriteLine($"Outer class: {outerClass.Name}");
|
||||
Console.WriteLine($"Number of members: {outerClass.Members.Count}");
|
||||
Console.WriteLine($"Number of nested types: {outerClass.NestedTypes.Count}");
|
||||
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($" - Nested type: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Parse failed!");
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
Console.WriteLine($"Error: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using MarketAlly.IronJava.Core.AST.Transformation;
|
||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||
using MarketAlly.IronJava.Core.Serialization;
|
||||
|
||||
namespace MarketAlly.IronJava.Sample
|
||||
namespace IronJava.Sample
|
||||
{
|
||||
class Program
|
||||
{
|
||||
@@ -15,6 +15,15 @@ namespace MarketAlly.IronJava.Sample
|
||||
Console.WriteLine("IronJava Sample Application");
|
||||
Console.WriteLine("===========================\n");
|
||||
|
||||
// Test nested types
|
||||
TestNestedTypes();
|
||||
Console.WriteLine("\n===========================\n");
|
||||
|
||||
// Test annotations
|
||||
TestAnnotations();
|
||||
Console.WriteLine("\n===========================\n");
|
||||
|
||||
|
||||
// Sample Java code
|
||||
string javaCode = @"
|
||||
package com.example;
|
||||
@@ -219,6 +228,171 @@ class User {
|
||||
Console.WriteLine($"\nMethods that throw exceptions: {throwingMethods.Count}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static void TestNestedTypes()
|
||||
{
|
||||
Console.WriteLine("Testing Nested Types Feature");
|
||||
Console.WriteLine("----------------------------");
|
||||
|
||||
var javaCode = @"
|
||||
public class OuterClass {
|
||||
private int outerField;
|
||||
|
||||
public class InnerClass {
|
||||
private String innerField;
|
||||
|
||||
public void innerMethod() {
|
||||
System.out.println(innerField);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StaticNestedClass {
|
||||
private static int staticField;
|
||||
}
|
||||
|
||||
public interface NestedInterface {
|
||||
void doSomething();
|
||||
}
|
||||
|
||||
public enum NestedEnum {
|
||||
VALUE1, VALUE2
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("✓ Parse successful!");
|
||||
var outerClass = result.Ast!.Types[0] as ClassDeclaration;
|
||||
if (outerClass != null)
|
||||
{
|
||||
Console.WriteLine($"\nOuter class: {outerClass.Name}");
|
||||
Console.WriteLine($" Members: {outerClass.Members.Count}");
|
||||
Console.WriteLine($" Nested types: {outerClass.NestedTypes.Count}");
|
||||
|
||||
foreach (var member in outerClass.Members)
|
||||
{
|
||||
if (member is FieldDeclaration field)
|
||||
{
|
||||
Console.WriteLine($" - Field: {field.Variables[0].Name}");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var nestedType in outerClass.NestedTypes)
|
||||
{
|
||||
Console.WriteLine($" - Nested: {nestedType.Name} ({nestedType.GetType().Name})");
|
||||
|
||||
if (nestedType is ClassDeclaration nestedClass)
|
||||
{
|
||||
Console.WriteLine($" Static: {nestedClass.Modifiers.HasFlag(Modifiers.Static)}");
|
||||
Console.WriteLine($" Members: {nestedClass.Members.Count}");
|
||||
}
|
||||
else if (nestedType is EnumDeclaration nestedEnum)
|
||||
{
|
||||
Console.WriteLine($" Constants: {nestedEnum.Constants.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("✗ Parse failed!");
|
||||
}
|
||||
}
|
||||
|
||||
static void TestAnnotations()
|
||||
{
|
||||
Console.WriteLine("Testing Annotation Parsing");
|
||||
Console.WriteLine("--------------------------");
|
||||
|
||||
var javaCode = @"
|
||||
@Entity
|
||||
@Table(name = ""users"")
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@GetMapping(""/users/{id}"")
|
||||
@ResponseBody
|
||||
public User getUser(@PathVariable Long id) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var result = JavaParser.Parse(javaCode);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
Console.WriteLine("✓ Parse successful!");
|
||||
|
||||
var userClass = result.Ast!.Types[0] as ClassDeclaration;
|
||||
if (userClass != null)
|
||||
{
|
||||
Console.WriteLine($"\nClass: {userClass.Name}");
|
||||
Console.WriteLine($" Class annotations: {userClass.Annotations.Count}");
|
||||
foreach (var annotation in userClass.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName} with {annotation.Arguments.Count} arguments");
|
||||
}
|
||||
|
||||
// Check fields
|
||||
var fields = userClass.Members.OfType<FieldDeclaration>().ToList();
|
||||
Console.WriteLine($"\n Fields: {fields.Count}");
|
||||
foreach (var field in fields)
|
||||
{
|
||||
Console.WriteLine($" - {field.Variables[0].Name}: {field.Annotations.Count} annotations");
|
||||
foreach (var annotation in field.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
}
|
||||
|
||||
// Check methods
|
||||
var methods = userClass.Members.OfType<MethodDeclaration>().ToList();
|
||||
Console.WriteLine($"\n Methods: {methods.Count}");
|
||||
foreach (var method in methods)
|
||||
{
|
||||
Console.WriteLine($" - {method.Name}: {method.Annotations.Count} annotations");
|
||||
foreach (var annotation in method.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
if (param.Annotations.Count > 0)
|
||||
{
|
||||
Console.WriteLine($" Parameter {param.Name}: {param.Annotations.Count} annotations");
|
||||
foreach (var annotation in param.Annotations)
|
||||
{
|
||||
var typeName = annotation.Type is ClassOrInterfaceType cit ? cit.Name : annotation.Type.ToString();
|
||||
Console.WriteLine($" - @{typeName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("✗ Parse failed!");
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
Console.WriteLine($" Error: {error.Message} at {error.Line}:{error.Column}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom visitor for code analysis
|
||||
|
||||
Reference in New Issue
Block a user