From 5ff7a358f955ef0aad9bd47e9b784ac96f3b8c48 Mon Sep 17 00:00:00 2001 From: ktkk Date: Wed, 8 Jul 2026 22:22:17 +0200 Subject: [PATCH] Format runtime visible/invisible type annotations attributes --- src/Class/AttributeInfo.zig | 193 +++++++++++++++++- .../classes/java/CustomTypeAnnotation.java | 9 + testsuite/classes/java/GenericClass.java | 14 ++ 3 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 testsuite/classes/java/CustomTypeAnnotation.java create mode 100644 testsuite/classes/java/GenericClass.java diff --git a/src/Class/AttributeInfo.zig b/src/Class/AttributeInfo.zig index 05ab95c..ceadc65 100644 --- a/src/Class/AttributeInfo.zig +++ b/src/Class/AttributeInfo.zig @@ -295,11 +295,13 @@ pub const AttributeInfo = union(enum) { _ = try w.write("predefined: yes\n"); try w.splatByteAll(' ', depth * indent); - try w.print("type: {s}\n", .{ @tagName(predefined) }); + try w.print("type: {t}\n", .{ predefined }); switch (predefined) { .constant_value => |attr| { const constant_value = attr.constantValue(constant_pool) catch return error.WriteFailed; + try w.splatByteAll(' ', depth * indent); + _ = try w.write("constant_value:\n"); try constant_value.indentedFormat(w, depth, indent + 1, constant_pool); }, .code => |attr| { @@ -513,9 +515,37 @@ pub const AttributeInfo = union(enum) { try parameter_annotation.indentedFormat(w, depth, parameter_annotation_indent + 1, constant_pool); } }, - //.runtime_visible_type_annotations, - //.runtime_invisible_type_annotations, - //.annotation_default, + .runtime_visible_type_annotations => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("type_annotations:\n"); + var type_annotation_indent = indent; + for (attr.type_annotations, 0..) |type_annotation, i| { + type_annotation_indent += 1; + defer type_annotation_indent -= 1; + + try w.splatByteAll(' ', depth * type_annotation_indent); + try w.print("{d}:\n", .{ i }); + try type_annotation.indentedFormat(w, depth, type_annotation_indent + 1, constant_pool); + } + }, + .runtime_invisible_type_annotations => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("type_annotations:\n"); + var type_annotation_indent = indent; + for (attr.type_annotations, 0..) |type_annotation, i| { + type_annotation_indent += 1; + defer type_annotation_indent -= 1; + + try w.splatByteAll(' ', depth * type_annotation_indent); + try w.print("{d}:\n", .{ i }); + try type_annotation.indentedFormat(w, depth, type_annotation_indent + 1, constant_pool); + } + }, + .annotation_default => |attr| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("default_value:\n"); + try attr.default_value.indentedFormat(w, depth, indent + 1, constant_pool); + }, .bootstrap_methods => |attr| { try w.splatByteAll(' ', depth * indent); _ = try w.write("bootstrap_methods:\n"); @@ -613,7 +643,6 @@ pub const AttributeInfo = union(enum) { try info.indentedFormat(w, depth, class_indent + 1, constant_pool); } }, - else => {}, } }, } @@ -1971,6 +2000,22 @@ pub const TypeAnnotation = struct { start_pc: u16, length: u16, index: u16, + + pub fn indentedFormat( + self: *const Entry, + w: *std.Io.Writer, + depth: usize, + indent: u8, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("start_pc: {d}\n", .{ self.start_pc }); + + try w.splatByteAll(' ', depth * indent); + try w.print("length: {d}\n", .{ self.length }); + + try w.splatByteAll(' ', depth * indent); + try w.print("start_pc: {d}\n", .{ self.index }); + } }; }; @@ -1986,6 +2031,72 @@ pub const TypeAnnotation = struct { offset: u16, type_argument_index: u8, }; + + pub fn indentedFormat( + self: *const TargetInfo, + w: *std.Io.Writer, + depth: usize, + indent: u8, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("target_info_type: {t}\n", .{ self.* }); + + switch (self.*) { + .type_parameter => |*type_parameter| { + try w.splatByteAll(' ', depth * indent); + try w.print("type_parameter_index: {d}\n", .{ type_parameter.type_parameter_index }); + }, + .supertype => |*supertype| { + try w.splatByteAll(' ', depth * indent); + try w.print("supertype_index: {d}\n", .{ supertype.supertype_index }); + }, + .type_parameter_bound => |*type_parameter_bound| { + try w.splatByteAll(' ', depth * indent); + try w.print("type_parameter_index: {d}\n", .{ type_parameter_bound.type_parameter_index }); + + try w.splatByteAll(' ', depth * indent); + try w.print("bound_index: {d}\n", .{ type_parameter_bound.bound_index }); + }, + .formal_parameter => |*formal_parameter| { + try w.splatByteAll(' ', depth * indent); + try w.print("formal_parameter_index: {d}\n", .{ formal_parameter.formal_parameter_index }); + }, + .throws => |*throws| { + try w.splatByteAll(' ', depth * indent); + try w.print("throws_type_index: {d}\n", .{ throws.throws_type_index }); + }, + .localvar => |*localvar| { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("table:\n"); + var entry_indent = indent; + for (localvar.table, 0..) |*entry, i| { + entry_indent += 1; + defer entry_indent -= 1; + + try w.splatByteAll(' ', depth * entry_indent); + try w.print("{d}:\n", .{ i }); + + try entry.indentedFormat(w, depth, indent); + } + }, + .@"catch" => |*@"catch"| { + try w.splatByteAll(' ', depth * indent); + try w.print("exception_table_index: {d}\n", .{ @"catch".exception_table_index }); + }, + .offset => |*offset| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset: {d}\n", .{ offset.offset }); + }, + .type_argument => |*type_argument| { + try w.splatByteAll(' ', depth * indent); + try w.print("offset: {d}\n", .{ type_argument.offset }); + + try w.splatByteAll(' ', depth * indent); + try w.print("type_argument_index: {d}\n", .{ type_argument.type_argument_index }); + }, + else => {}, + } + } }; pub const TypePath = struct { @@ -1994,6 +2105,19 @@ pub const TypeAnnotation = struct { pub const Path = struct { type_path_kind: u8, type_argument_index: u8, + + pub fn indentedFormat( + self: *const Path, + w: *std.Io.Writer, + depth: usize, + indent: u8, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("type_path_kind: {d}\n", .{ self.type_path_kind }); + + try w.splatByteAll(' ', depth * indent); + try w.print("type_argument_index: {d}\n", .{ self.type_argument_index }); + } }; pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!TypePath { @@ -2015,6 +2139,25 @@ pub const TypeAnnotation = struct { pub fn deinit(self: *TypePath, allocator: std.mem.Allocator) void { allocator.free(self.paths); } + + pub fn indentedFormat( + self: *const TypePath, + w: *std.Io.Writer, + depth: usize, + indent: u8, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + _ = try w.write("paths:\n"); + var path_indent = indent; + for (self.paths, 0..) |path, i| { + path_indent += 1; + defer path_indent -= 1; + + try w.splatByteAll(' ', depth * path_indent); + try w.print("{d}:\n", .{ i }); + try path.indentedFormat(w, depth, path_indent + 1); + } + } }; pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self { @@ -2119,6 +2262,46 @@ pub const TypeAnnotation = struct { } allocator.free(self.element_value_pairs); } + + pub fn indentedFormat( + self: *const Self, + w: *std.Io.Writer, + depth: usize, + indent: u8, + constant_pool: ConstantPool, + ) std.Io.Writer.Error!void { + try w.splatByteAll(' ', depth * indent); + try w.print("target_type: {t}\n", .{ self.target_type }); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("target_info:\n"); + try self.target_info.indentedFormat(w, depth + 1, indent); + + try w.splatByteAll(' ', depth * indent); + _ = try w.write("target_path:\n"); + try self.target_path.indentedFormat(w, depth + 1, indent); + + 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); + } }; pub const RuntimeVisibleTypeAnnotations = struct { diff --git a/testsuite/classes/java/CustomTypeAnnotation.java b/testsuite/classes/java/CustomTypeAnnotation.java new file mode 100644 index 0000000..b6572f7 --- /dev/null +++ b/testsuite/classes/java/CustomTypeAnnotation.java @@ -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.TYPE_PARAMETER) +public @interface CustomTypeAnnotation { +} diff --git a/testsuite/classes/java/GenericClass.java b/testsuite/classes/java/GenericClass.java new file mode 100644 index 0000000..151a15a --- /dev/null +++ b/testsuite/classes/java/GenericClass.java @@ -0,0 +1,14 @@ +import java.util.function.Supplier; + +public class GenericClass<@CustomTypeAnnotation T> { + + public Supplier getSupplier(T value) { + return new Supplier() { + @Override + public T get() { + return value; + } + }; + } + +}