Format annotation attributes
This commit is contained in:
parent
3a5fd90d14
commit
f12bcd2911
6 changed files with 275 additions and 16 deletions
|
|
@ -447,10 +447,58 @@ pub const AttributeInfo = union(enum) {
|
|||
}
|
||||
},
|
||||
.deprecated => {},
|
||||
//.runtime_visible_annotations,
|
||||
//.runtime_invisible_annotations,
|
||||
//.runtime_visible_parameter_annotations,
|
||||
//.runtime_invisible_parameter_annotations,
|
||||
.runtime_visible_annotations => |attr| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("annotations:\n");
|
||||
var annotation_indent = indent;
|
||||
for (attr.annotations, 0..) |annotation, i| {
|
||||
annotation_indent += 1;
|
||||
defer annotation_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * annotation_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
||||
}
|
||||
},
|
||||
.runtime_invisible_annotations => |attr| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("annotations:\n");
|
||||
var annotation_indent = indent;
|
||||
for (attr.annotations, 0..) |annotation, i| {
|
||||
annotation_indent += 1;
|
||||
defer annotation_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * annotation_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
||||
}
|
||||
},
|
||||
.runtime_visible_parameter_annotations => |attr| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("parameter_annotations:\n");
|
||||
var parameter_annotation_indent = indent;
|
||||
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
|
||||
parameter_annotation_indent += 1;
|
||||
defer parameter_annotation_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * parameter_annotation_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
|
||||
}
|
||||
},
|
||||
.runtime_invisible_parameter_annotations => |attr| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("parameter_annotations:\n");
|
||||
var parameter_annotation_indent = indent;
|
||||
for (attr.parameter_annotations, 0..) |parameter_annotation, i| {
|
||||
parameter_annotation_indent += 1;
|
||||
defer parameter_annotation_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * parameter_annotation_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool);
|
||||
}
|
||||
},
|
||||
//.runtime_visible_type_annotations,
|
||||
//.runtime_invisible_type_annotations,
|
||||
//.annotation_default,
|
||||
|
|
@ -1381,14 +1429,11 @@ pub const Deprecated = struct { };
|
|||
|
||||
pub const ElementValue = union(enum) {
|
||||
// B, C, D, F, I, J, S, Z, s
|
||||
const_value_index: u16,
|
||||
const_value: ConstValue,
|
||||
// e
|
||||
enum_const_value: struct {
|
||||
type_name_index: u16,
|
||||
const_name_index: u16,
|
||||
},
|
||||
enum_const_value: EnumConstValue,
|
||||
// c
|
||||
class_info_index: u16,
|
||||
class_const_value: ClassConstValue,
|
||||
// @
|
||||
annotation_value: Annotation,
|
||||
// [
|
||||
|
|
@ -1396,11 +1441,78 @@ pub const ElementValue = union(enum) {
|
|||
values: []ElementValue,
|
||||
},
|
||||
|
||||
pub const ConstValue = struct {
|
||||
@"type": Type,
|
||||
index: u16,
|
||||
|
||||
pub const Type = enum(u8) {
|
||||
byte = 'B',
|
||||
char = 'C',
|
||||
double = 'D',
|
||||
float = 'F',
|
||||
int = 'I',
|
||||
long = 'J',
|
||||
short = 'S',
|
||||
boolean = 'Z',
|
||||
string = 's',
|
||||
};
|
||||
|
||||
pub fn value(self: *const ConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
const value_ = try constant_pool.get(self.index);
|
||||
return switch (self.@"type") {
|
||||
.byte, .char, .int, .short, .boolean => blk: {
|
||||
if (!value_.is(.integer)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk value_;
|
||||
},
|
||||
.double => blk: {
|
||||
if (!value_.is(.double)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk value_;
|
||||
},
|
||||
.float => blk: {
|
||||
if (!value_.is(.float)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk value_;
|
||||
},
|
||||
.long => blk: {
|
||||
if (!value_.is(.long)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk value_;
|
||||
},
|
||||
.string => blk: {
|
||||
if (!value_.is(.utf8)) break :blk ResolveError.InvalidConstantType;
|
||||
break :blk value_;
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const EnumConstValue = struct {
|
||||
type_name_index: u16,
|
||||
const_name_index: u16,
|
||||
|
||||
pub fn descriptor(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.type_name_index, .utf8);
|
||||
}
|
||||
|
||||
pub fn name(self: *const EnumConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.const_name_index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ClassConstValue = struct {
|
||||
index: u16,
|
||||
|
||||
pub fn descriptor(self: *const ClassConstValue, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.index, .utf8);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!ElementValue {
|
||||
const tag = try input.takeByte();
|
||||
return switch (tag) {
|
||||
'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's' => .{
|
||||
.const_value_index = try input.takeInt(u16, .big),
|
||||
.const_value = .{
|
||||
.@"type" = @enumFromInt(tag),
|
||||
.index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
'e' => .{
|
||||
.enum_const_value = .{
|
||||
|
|
@ -1409,7 +1521,9 @@ pub const ElementValue = union(enum) {
|
|||
},
|
||||
},
|
||||
'c' => .{
|
||||
.class_info_index = try input.takeInt(u16, .big),
|
||||
.class_const_value = .{
|
||||
.index = try input.takeInt(u16, .big),
|
||||
},
|
||||
},
|
||||
'@' => .{
|
||||
.annotation_value = try .parse(input, allocator),
|
||||
|
|
@ -1444,6 +1558,61 @@ pub const ElementValue = union(enum) {
|
|||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indentedFormat(
|
||||
self: *const ElementValue,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
try w.print("type: {s}\n", .{ @tagName(self.*) });
|
||||
|
||||
switch (self.*) {
|
||||
.const_value => |const_value| {
|
||||
const value = const_value.value(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("value:\n");
|
||||
try value.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.enum_const_value => |enum_const_value| {
|
||||
const descriptor = enum_const_value.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
try descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
const name = enum_const_value.name(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
try name.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.class_const_value => |class_const_value| {
|
||||
const descriptor = class_const_value.descriptor(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("descriptor:\n");
|
||||
try descriptor.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.annotation_value => |annotation_value| {
|
||||
_ = try w.write("annotation:\n");
|
||||
try annotation_value.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
},
|
||||
.array_value => |array_value| {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("values:\n");
|
||||
var value_indent = indent;
|
||||
for (array_value.values, 0..) |*value, i| {
|
||||
value_indent += 1;
|
||||
defer value_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * value_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
|
||||
try value.indentedFormat(w, depth, value_indent + 1, constant_pool);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const ElementValuePair = struct {
|
||||
|
|
@ -1452,6 +1621,23 @@ pub const ElementValuePair = struct {
|
|||
|
||||
const Self = @This();
|
||||
|
||||
pub fn indentedFormat(
|
||||
self: *const ElementValuePair,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
const element_name = self.elementName(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("name:\n");
|
||||
try element_name.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("value:\n");
|
||||
try self.value.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
}
|
||||
|
||||
pub fn elementName(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.element_name_index, .utf8);
|
||||
}
|
||||
|
|
@ -1489,6 +1675,31 @@ pub const Annotation = struct {
|
|||
allocator.free(self.element_value_pairs);
|
||||
}
|
||||
|
||||
pub fn indentedFormat(
|
||||
self: *const Annotation,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
const type_ = self.@"type"(constant_pool) catch return error.WriteFailed;
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("type:\n");
|
||||
try type_.indentedFormat(w, depth, indent + 1, constant_pool);
|
||||
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("element_value_pairs:\n");
|
||||
var element_value_pair_indent = indent;
|
||||
for (self.element_value_pairs, 0..) |element_value_pair, i| {
|
||||
element_value_pair_indent += 1;
|
||||
defer element_value_pair_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * element_value_pair_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try element_value_pair.indentedFormat(w, depth, element_value_pair_indent + 1, constant_pool);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn @"type"(self: *const Self, constant_pool: ConstantPool) ResolveError!ConstantPool.Info {
|
||||
return constant_pool.getTag(self.type_index, .utf8);
|
||||
}
|
||||
|
|
@ -1548,6 +1759,26 @@ pub const RuntimeInvisibleAnnotations = struct {
|
|||
|
||||
pub const ParameterAnnotation = struct {
|
||||
annotations: []Annotation,
|
||||
|
||||
pub fn indentedFormat(
|
||||
self: *const ParameterAnnotation,
|
||||
w: *std.Io.Writer,
|
||||
depth: usize,
|
||||
indent: u8,
|
||||
constant_pool: ConstantPool,
|
||||
) std.Io.Writer.Error!void {
|
||||
try w.splatByteAll(' ', depth * indent);
|
||||
_ = try w.write("annotations:\n");
|
||||
var annotation_indent = indent;
|
||||
for (self.annotations, 0..) |annotation, i| {
|
||||
annotation_indent += 1;
|
||||
defer annotation_indent -= 1;
|
||||
|
||||
try w.splatByteAll(' ', depth * annotation_indent);
|
||||
try w.print("{d}:\n", .{ i });
|
||||
try annotation.indentedFormat(w, depth, annotation_indent + 1, constant_pool);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const RuntimeVisibleParameterAnnotations = struct {
|
||||
|
|
|
|||
14
testsuite/classes/java/CustomAnnotation.java
Normal file
14
testsuite/classes/java/CustomAnnotation.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@CustomAnnotationAnnotation
|
||||
public @interface CustomAnnotation {
|
||||
public CustomAnnotationType type();
|
||||
|
||||
public String name() default "Bob";
|
||||
}
|
||||
|
||||
9
testsuite/classes/java/CustomAnnotationAnnotation.java
Normal file
9
testsuite/classes/java/CustomAnnotationAnnotation.java
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface CustomAnnotationAnnotation { }
|
||||
|
||||
5
testsuite/classes/java/CustomAnnotationType.java
Normal file
5
testsuite/classes/java/CustomAnnotationType.java
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
public enum CustomAnnotationType {
|
||||
ONE,
|
||||
TWO,
|
||||
}
|
||||
|
||||
|
|
@ -4,7 +4,6 @@ import java.lang.annotation.Target;
|
|||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface CustomAttribute {
|
||||
}
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface CustomParameterAnnotation { }
|
||||
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
import java.util.function.Supplier;
|
||||
|
||||
@CustomAnnotation(type = CustomAnnotationType.ONE, name = "Alice")
|
||||
public class Main implements Runnable, Supplier<Integer>, Interface {
|
||||
private static final String name = "John";
|
||||
private static final int number = 42;
|
||||
private static final double funnyNumber = 6.9;
|
||||
|
||||
public static void main(String[] args) {
|
||||
public static void main(@CustomParameterAnnotation String[] args) {
|
||||
final var main = new Main();
|
||||
main.sayHello();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue