Fixed annotation parsing in AstBuilder
pulled some hair out on this one
This commit is contained in:
@@ -297,11 +297,24 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
var annotations = new List<Annotation>();
|
var annotations = new List<Annotation>();
|
||||||
foreach (var context in contexts)
|
foreach (var context in contexts)
|
||||||
{
|
{
|
||||||
|
// Check if this is directly an annotation context
|
||||||
if (context is Java9Parser.AnnotationContext annotationContext)
|
if (context is Java9Parser.AnnotationContext annotationContext)
|
||||||
{
|
{
|
||||||
var annotation = BuildAnnotation(annotationContext);
|
var annotation = BuildAnnotation(annotationContext);
|
||||||
if (annotation != null) annotations.Add(annotation);
|
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;
|
return annotations;
|
||||||
}
|
}
|
||||||
@@ -312,25 +325,37 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
TypeReference? type = null;
|
TypeReference? type = null;
|
||||||
var arguments = new List<AnnotationArgument>();
|
var arguments = new List<AnnotationArgument>();
|
||||||
|
|
||||||
|
|
||||||
// Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
|
// Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
|
||||||
if (context.normalAnnotation() != null)
|
if (context.normalAnnotation() != null)
|
||||||
{
|
{
|
||||||
var normalAnn = context.normalAnnotation();
|
var normalAnn = context.normalAnnotation();
|
||||||
type = BuildTypeReference(normalAnn.typeName());
|
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)
|
if (normalAnn.elementValuePairList() != null)
|
||||||
{
|
{
|
||||||
foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
|
foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
|
||||||
{
|
{
|
||||||
var name = pair.identifier().GetText();
|
var name = pair.identifier().GetText();
|
||||||
var value = BuildExpression(pair.elementValue());
|
var value = BuildElementValue(pair.elementValue());
|
||||||
if (value != null)
|
|
||||||
|
// 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(
|
var elementText = pair.elementValue().GetText();
|
||||||
GetSourceRange(pair), name, value
|
value = new LiteralExpression(GetSourceRange(pair.elementValue()), elementText, LiteralKind.String);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arguments.Add(new AnnotationValueArgument(
|
||||||
|
GetSourceRange(pair), name, value
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,30 +363,89 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
{
|
{
|
||||||
var markerAnn = context.markerAnnotation();
|
var markerAnn = context.markerAnnotation();
|
||||||
type = BuildTypeReference(markerAnn.typeName());
|
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
|
// Marker annotations have no arguments
|
||||||
}
|
}
|
||||||
else if (context.singleElementAnnotation() != null)
|
else if (context.singleElementAnnotation() != null)
|
||||||
{
|
{
|
||||||
var singleAnn = context.singleElementAnnotation();
|
var singleAnn = context.singleElementAnnotation();
|
||||||
type = BuildTypeReference(singleAnn.typeName());
|
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)
|
if (singleAnn.elementValue() != null)
|
||||||
{
|
{
|
||||||
var value = BuildExpression(singleAnn.elementValue());
|
var value = BuildElementValue(singleAnn.elementValue());
|
||||||
if (value != null)
|
|
||||||
|
// Fallback if BuildElementValue returns null
|
||||||
|
if (value == null)
|
||||||
{
|
{
|
||||||
arguments.Add(new AnnotationValueArgument(
|
var elementText = singleAnn.elementValue().GetText();
|
||||||
location, "value", value
|
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;
|
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)
|
private List<TypeParameter> BuildTypeParameters(Java9Parser.TypeParametersContext? context)
|
||||||
{
|
{
|
||||||
if (context == null) return new List<TypeParameter>();
|
if (context == null) return new List<TypeParameter>();
|
||||||
@@ -414,8 +498,8 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
Java9Parser.ArrayTypeContext array => BuildArrayType(array),
|
Java9Parser.ArrayTypeContext array => BuildArrayType(array),
|
||||||
Java9Parser.TypeVariableContext typeVar => BuildTypeVariable(typeVar),
|
Java9Parser.TypeVariableContext typeVar => BuildTypeVariable(typeVar),
|
||||||
Java9Parser.ClassTypeContext classType => BuildClassType(classType),
|
Java9Parser.ClassTypeContext classType => BuildClassType(classType),
|
||||||
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
|
||||||
Java9Parser.TypeNameContext typeName => BuildTypeName(typeName),
|
Java9Parser.TypeNameContext typeName => BuildTypeName(typeName),
|
||||||
|
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -980,6 +1064,13 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
|
|
||||||
private Parameter? BuildLastParameter(Java9Parser.LastFormalParameterContext context)
|
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 location = GetSourceRange(context);
|
||||||
var modifiers = BuildModifiers(context.variableModifier());
|
var modifiers = BuildModifiers(context.variableModifier());
|
||||||
var annotations = BuildAnnotations(context.variableModifier());
|
var annotations = BuildAnnotations(context.variableModifier());
|
||||||
@@ -989,7 +1080,7 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
var declaratorId = context.variableDeclaratorId();
|
var declaratorId = context.variableDeclaratorId();
|
||||||
var name = declaratorId.identifier().GetText();
|
var name = declaratorId.identifier().GetText();
|
||||||
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
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);
|
return new Parameter(location, type, name, isVarArgs, isFinal, annotations);
|
||||||
}
|
}
|
||||||
@@ -1325,7 +1416,7 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
|
|
||||||
if (context.defaultValue() != null)
|
if (context.defaultValue() != null)
|
||||||
{
|
{
|
||||||
defaultValue = BuildExpression(context.defaultValue().elementValue());
|
defaultValue = BuildElementValue(context.defaultValue().elementValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AnnotationMember(location, name, type, defaultValue);
|
return new AnnotationMember(location, name, type, defaultValue);
|
||||||
@@ -2590,46 +2681,6 @@ namespace MarketAlly.IronJava.Core.AST.Builders
|
|||||||
return parameters;
|
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
|
// Statement building methods
|
||||||
|
|
||||||
|
|||||||
@@ -400,6 +400,23 @@ namespace MarketAlly.IronJava.Core.AST.Nodes
|
|||||||
public override void Accept(IJavaVisitor visitor) => visitor.VisitArrayInitializer(this);
|
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>
|
/// <summary>
|
||||||
/// Represents a lambda expression.
|
/// Represents a lambda expression.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
|||||||
void VisitNewExpression(NewExpression node);
|
void VisitNewExpression(NewExpression node);
|
||||||
void VisitNewArrayExpression(NewArrayExpression node);
|
void VisitNewArrayExpression(NewArrayExpression node);
|
||||||
void VisitArrayInitializer(ArrayInitializer node);
|
void VisitArrayInitializer(ArrayInitializer node);
|
||||||
|
void VisitAnnotationExpression(AnnotationExpression node);
|
||||||
void VisitLambdaExpression(LambdaExpression node);
|
void VisitLambdaExpression(LambdaExpression node);
|
||||||
void VisitLambdaParameter(LambdaParameter node);
|
void VisitLambdaParameter(LambdaParameter node);
|
||||||
void VisitMethodReferenceExpression(MethodReferenceExpression node);
|
void VisitMethodReferenceExpression(MethodReferenceExpression node);
|
||||||
@@ -135,6 +136,7 @@ namespace MarketAlly.IronJava.Core.AST.Visitors
|
|||||||
T VisitNewExpression(NewExpression node);
|
T VisitNewExpression(NewExpression node);
|
||||||
T VisitNewArrayExpression(NewArrayExpression node);
|
T VisitNewArrayExpression(NewArrayExpression node);
|
||||||
T VisitArrayInitializer(ArrayInitializer node);
|
T VisitArrayInitializer(ArrayInitializer node);
|
||||||
|
T VisitAnnotationExpression(AnnotationExpression node);
|
||||||
T VisitLambdaExpression(LambdaExpression node);
|
T VisitLambdaExpression(LambdaExpression node);
|
||||||
T VisitLambdaParameter(LambdaParameter node);
|
T VisitLambdaParameter(LambdaParameter node);
|
||||||
T VisitMethodReferenceExpression(MethodReferenceExpression 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 VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||||
public virtual void VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
public virtual void VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||||
public virtual void VisitArrayInitializer(ArrayInitializer 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 VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||||
public virtual void VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
public virtual void VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||||
public virtual void VisitMethodReferenceExpression(MethodReferenceExpression 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 VisitNewExpression(NewExpression node) => DefaultVisit(node);
|
||||||
public virtual T VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
public virtual T VisitNewArrayExpression(NewArrayExpression node) => DefaultVisit(node);
|
||||||
public virtual T VisitArrayInitializer(ArrayInitializer 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 VisitLambdaExpression(LambdaExpression node) => DefaultVisit(node);
|
||||||
public virtual T VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
public virtual T VisitLambdaParameter(LambdaParameter node) => DefaultVisit(node);
|
||||||
public virtual T VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
public virtual T VisitMethodReferenceExpression(MethodReferenceExpression node) => DefaultVisit(node);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<!-- NuGet Package Metadata -->
|
<!-- NuGet Package Metadata -->
|
||||||
<PackageId>IronJava</PackageId>
|
<PackageId>IronJava</PackageId>
|
||||||
<Version>2.1.1</Version>
|
<Version>2.1.2</Version>
|
||||||
<Authors>David H Friedel Jr</Authors>
|
<Authors>David H Friedel Jr</Authors>
|
||||||
<Company>MarketAlly</Company>
|
<Company>MarketAlly</Company>
|
||||||
<Title>IronJava</Title>
|
<Title>IronJava</Title>
|
||||||
|
|||||||
@@ -416,6 +416,22 @@ namespace MarketAlly.IronJava.Core.Serialization
|
|||||||
return result;
|
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)
|
public override Dictionary<string, object?> VisitJavaDoc(JavaDoc node)
|
||||||
{
|
{
|
||||||
var result = CreateBaseNode(node);
|
var result = CreateBaseNode(node);
|
||||||
@@ -561,6 +577,13 @@ namespace MarketAlly.IronJava.Core.Serialization
|
|||||||
return result;
|
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)
|
public override Dictionary<string, object?> VisitMethodReferenceExpression(MethodReferenceExpression node)
|
||||||
{
|
{
|
||||||
var result = CreateBaseNode(node);
|
var result = CreateBaseNode(node);
|
||||||
@@ -747,6 +770,9 @@ namespace MarketAlly.IronJava.Core.Serialization
|
|||||||
"InstanceOfExpression" => DeserializeInstanceOfExpression(element, location),
|
"InstanceOfExpression" => DeserializeInstanceOfExpression(element, location),
|
||||||
"NewArrayExpression" => DeserializeNewArrayExpression(element, location),
|
"NewArrayExpression" => DeserializeNewArrayExpression(element, location),
|
||||||
"ArrayInitializer" => DeserializeArrayInitializer(element, location),
|
"ArrayInitializer" => DeserializeArrayInitializer(element, location),
|
||||||
|
"AnnotationExpression" => DeserializeAnnotationExpression(element, location),
|
||||||
|
"AnnotationValueArgument" => DeserializeAnnotationValueArgument(element, location),
|
||||||
|
"AnnotationArrayArgument" => DeserializeAnnotationArrayArgument(element, location),
|
||||||
"MethodReferenceExpression" => DeserializeMethodReferenceExpression(element, location),
|
"MethodReferenceExpression" => DeserializeMethodReferenceExpression(element, location),
|
||||||
"ClassLiteralExpression" => DeserializeClassLiteralExpression(element, location),
|
"ClassLiteralExpression" => DeserializeClassLiteralExpression(element, location),
|
||||||
"LocalVariableStatement" => DeserializeLocalVariableStatement(element, location),
|
"LocalVariableStatement" => DeserializeLocalVariableStatement(element, location),
|
||||||
@@ -1282,6 +1308,30 @@ namespace MarketAlly.IronJava.Core.Serialization
|
|||||||
return new ArrayInitializer(location, elements);
|
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)
|
private MethodReferenceExpression DeserializeMethodReferenceExpression(JsonElement element, SourceRange location)
|
||||||
{
|
{
|
||||||
var target = Deserialize(element.GetProperty("target")) as Expression ?? throw new JsonException("target is not Expression");
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ using MarketAlly.IronJava.Core.AST.Transformation;
|
|||||||
using MarketAlly.IronJava.Core.AST.Visitors;
|
using MarketAlly.IronJava.Core.AST.Visitors;
|
||||||
using MarketAlly.IronJava.Core.Serialization;
|
using MarketAlly.IronJava.Core.Serialization;
|
||||||
|
|
||||||
namespace MarketAlly.IronJava.Sample
|
namespace IronJava.Sample
|
||||||
{
|
{
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
@@ -19,6 +19,11 @@ namespace MarketAlly.IronJava.Sample
|
|||||||
TestNestedTypes();
|
TestNestedTypes();
|
||||||
Console.WriteLine("\n===========================\n");
|
Console.WriteLine("\n===========================\n");
|
||||||
|
|
||||||
|
// Test annotations
|
||||||
|
TestAnnotations();
|
||||||
|
Console.WriteLine("\n===========================\n");
|
||||||
|
|
||||||
|
|
||||||
// Sample Java code
|
// Sample Java code
|
||||||
string javaCode = @"
|
string javaCode = @"
|
||||||
package com.example;
|
package com.example;
|
||||||
@@ -296,6 +301,98 @@ public class OuterClass {
|
|||||||
Console.WriteLine("✗ Parse failed!");
|
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
|
// Custom visitor for code analysis
|
||||||
|
|||||||
Reference in New Issue
Block a user