Add runtime visible/invisible type annotations attributes

This commit is contained in:
ktkk 2026-07-08 14:24:18 +00:00
parent 89e548c8cc
commit a47405e903

View file

@ -28,8 +28,8 @@ pub const AttributeInfo = union(enum) {
runtime_invisible_annotations: RuntimeInvisibleAnnotations,
runtime_visible_parameter_annotations: RuntimeVisibleParameterAnnotations,
runtime_invisible_parameter_annotations: RuntimeInvisibleParameterAnnotations,
// runtime_visible_type_annotations: RuntimeVisibleTypeAnnotations,
// runtime_invisible_type_annotations: RuntimeInvisibleTypeAnnotations,
runtime_visible_type_annotations: RuntimeVisibleTypeAnnotations,
runtime_invisible_type_annotations: RuntimeInvisibleTypeAnnotations,
annotation_default: AnnotationDefault,
bootstrap_methods: BootstrapMethods,
method_parameters: MethodParameters,
@ -163,6 +163,18 @@ pub const AttributeInfo = union(enum) {
.runtime_invisible_parameter_annotations = try RuntimeInvisibleParameterAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, name, "RuntimeVisibleTypeAnnotations")) {
return .{
.predefined = .{
.runtime_invisible_type_annotations = try RuntimeInvisibleTypeAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, name, "RuntimeInvisibleTypeAnnotations")) {
return .{
.predefined = .{
.runtime_invisible_type_annotations = try RuntimeInvisibleTypeAnnotations.parse(limited, allocator),
},
};
} else if (std.mem.eql(u8, name, "AnnotationDefault")) {
return .{
.predefined = .{
@ -246,6 +258,8 @@ pub const AttributeInfo = union(enum) {
.runtime_invisible_annotations => |*runtime_invisible_annotations| runtime_invisible_annotations.deinit(allocator),
.runtime_visible_parameter_annotations => |*runtime_visible_parameter_annotations| runtime_visible_parameter_annotations.deinit(allocator),
.runtime_invisible_parameter_annotations => |*runtime_invisible_parameter_annotations| runtime_invisible_parameter_annotations.deinit(allocator),
.runtime_visible_type_annotations => |*runtime_visible_type_annotations| runtime_visible_type_annotations.deinit(allocator),
.runtime_invisible_type_annotations => |*runtime_invisible_type_annotations| runtime_invisible_type_annotations.deinit(allocator),
.annotation_default => |*annotation_default| annotation_default.deinit(allocator),
.bootstrap_methods => |*bootstrap_methods| bootstrap_methods.deinit(allocator),
.method_parameters => |*method_parameters| method_parameters.deinit(allocator),
@ -1857,50 +1871,307 @@ pub const RuntimeInvisibleParameterAnnotations = struct {
}
};
// TODO: TypeAnnotation structure
// pub const TypeAnnotation = struct {
// target_info: union(TargetType) {
// type_parameter_target: TypeParameterTarget,
// supertype_target: SupertypeTarget,
// type_parameter_bound_target: TypeParameterBoundTarget,
// emtpy_target: EmptyTarget,
// formal_parameter_target: FormalParameterTarget,
// throws_target: ThrowsTarget,
// localvar_target: LocalvarTarget,
// catch_target: CatchTarget,
// offset_target: OffsetTarget,
// type_argument_target: TypeArgumentTarget,
// },
// target_path: TypePath,
// type_index: u16,
// element_value_pairs: []ElementValuePair,
//
// pub const TargetType = enum(u8) {
// type_parameter_target = 0x00,
// type
// };
//
// pub const TypePath = struct {
// path: []Path,
//
// pub const Path = struct {
// type_path_kind: u8,
// type_argument_index: u8,
// };
// };
// };
pub const TypeAnnotation = struct {
target_type: TargetType,
target_info: TargetInfo,
target_path: TypePath,
type_index: u16,
element_value_pairs: []ElementValuePair,
// pub const RuntimeVisibleTypeAnnotations = struct {
// type_annotations: []TypeAnnotation,
//
// const Self = @This();
// };
//
// pub const RuntimeInvisibleTypeAnnotations = struct {
// type_annotations: []TypeAnnotation,
//
// const Self = @This();
// };
const Self = @This();
pub const TargetType = enum(u8) {
/// type parameter declaration of generic class or interface
type_parameter_generic_class_interface = 0x00,
/// type parameter declaration of generic method or constructor
type_parameter_generic_method_constructor = 0x01,
/// type in extends or implements clause of class declaration
/// (including the direct superclass or direct superinterface of an anonymous class declaration),
/// or in extends clause of interface declaration
type_in_extends_implements = 0x10,
/// type in bound of type parameter declaration of generic class or interface
type_in_bound_generic_class_interface = 0x11,
/// type in bound of type parameter declaration of generic method or constructor
type_in_bound_generic_method_constructor = 0x12,
/// type in field or record component declaration
type_in_field_record_component = 0x13,
/// return type of method, or type of newly constructed object
return_type_method_newly_constructed_object = 0x14,
/// receiver type of method or constructor
receiver_type_method_constructor = 0x15,
/// type in formal parameter declaration of method, constructor, or lambda expression
type_in_formal_parameter_declaration_method_constructor_lambda = 0x16,
/// type in throws clause of method or constructor
type_in_throws_method_constructor = 0x17,
/// type in local variable declaration
type_in_local_variable = 0x40,
/// type in resource variable declaration
type_in_resource_variable = 0x41,
/// type in exception parameter declaration
type_in_exception_parameter = 0x42,
/// type in instanceof expression
type_in_instanceof = 0x43,
/// type in new expression
type_in_new = 0x44,
/// type in method reference expression using ::new
type_in_method_reference_new = 0x45,
/// type in method reference expression using ::Identifier
type_in_method_reference_identifier = 0x46,
/// type in cast expression
type_in_cast = 0x47,
/// type argument for generic constructor in new expression or explicit constructor invocation statement
type_generic_constructor_new_explicit = 0x48,
/// type argument for generic method in method invocation expression
type_generic_method_invocation = 0x49,
/// type argument for generic constructor in method reference expression using ::new
type_generic_constructor_method_reference_new = 0x4a,
/// type argument for generic method in method reference expression using ::Identifier
type_generic_method_method_reference_identifier = 0x4b,
};
pub const TargetInfo = union(enum) {
type_parameter: TypeParameter,
supertype: SuperType,
type_parameter_bound: TypeParameterBound,
empty: Empty,
formal_parameter: FormalParameter,
throws: Throws,
localvar: Localvar,
@"catch": Catch,
offset: Offset,
type_argument: TypeArgument,
pub const TypeParameter = struct {
type_parameter_index: u8,
};
pub const SuperType = struct {
supertype_index: u16,
};
pub const TypeParameterBound = struct {
type_parameter_index: u8,
bound_index: u8,
};
pub const Empty = struct { };
pub const FormalParameter = struct {
formal_parameter_index: u8,
};
pub const Throws = struct {
throws_type_index: u16,
};
pub const Localvar = struct {
table: []Entry,
pub const Entry = struct {
start_pc: u16,
length: u16,
index: u16,
};
};
pub const Catch = struct {
exception_table_index: u16,
};
pub const Offset = struct {
offset: u16,
};
pub const TypeArgument = struct {
offset: u16,
type_argument_index: u8,
};
};
pub const TypePath = struct {
paths: []Path,
pub const Path = struct {
type_path_kind: u8,
type_argument_index: u8,
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!TypePath {
const length = try input.takeByte();
const paths = try allocator.alloc(Path, length);
errdefer allocator.free(paths);
for (paths) |*path| {
path.* = .{
.type_path_kind = try input.takeByte(),
.type_argument_index = try input.takeByte(),
};
}
return .{
.paths = paths,
};
}
pub fn deinit(self: *TypePath, allocator: std.mem.Allocator) void {
allocator.free(self.paths);
}
};
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const target_type: TargetType = @enumFromInt(try input.takeInt(u8, .big));
const target_info: TargetInfo = switch (target_type) {
.type_parameter_generic_class_interface, .type_parameter_generic_method_constructor => .{
.type_parameter = .{
.type_parameter_index = try input.takeByte(),
},
},
.type_in_extends_implements => .{
.supertype = .{
.supertype_index = try input.takeInt(u16, .big),
},
},
.type_in_bound_generic_class_interface, .type_in_bound_generic_method_constructor => .{
.type_parameter_bound = .{
.type_parameter_index = try input.takeByte(),
.bound_index = try input.takeByte(),
},
},
.type_in_field_record_component, .return_type_method_newly_constructed_object, .receiver_type_method_constructor => .{
.empty = .{},
},
.type_in_formal_parameter_declaration_method_constructor_lambda => .{
.formal_parameter = .{
.formal_parameter_index = try input.takeByte(),
},
},
.type_in_throws_method_constructor => .{
.throws = .{
.throws_type_index = try input.takeInt(u16, .big),
},
},
.type_in_local_variable, .type_in_resource_variable => blk: {
const table_length = try input.takeInt(u16, .big);
const table = try allocator.alloc(TargetInfo.Localvar.Entry, table_length);
errdefer allocator.free(table);
for (table) |*entry| {
entry.* = .{
.start_pc = try input.takeInt(u16, .big),
.length = try input.takeInt(u16, .big),
.index = try input.takeInt(u16, .big),
};
}
break :blk .{
.localvar = .{
.table = table,
},
};
},
.type_in_exception_parameter => .{
.@"catch" = . {
.exception_table_index = try input.takeInt(u16, .big),
},
},
.type_in_instanceof, .type_in_new, .type_in_method_reference_new, .type_in_method_reference_identifier => .{
.offset = .{
.offset = try input.takeInt(u16, .big),
},
},
.type_in_cast, .type_generic_constructor_new_explicit, .type_generic_method_invocation, .type_generic_constructor_method_reference_new, .type_generic_method_method_reference_identifier => .{
.type_argument = .{
.offset = try input.takeInt(u16, .big),
.type_argument_index = try input.takeByte(),
},
},
};
var target_path: TypePath = try .parse(input, allocator);
errdefer target_path.deinit(allocator);
const type_index = try input.takeInt(u16, .big);
const num_element_value_pairs = try input.takeInt(u16, .big);
const element_value_pairs = try allocator.alloc(ElementValuePair, num_element_value_pairs);
errdefer allocator.free(element_value_pairs);
for (element_value_pairs) |*element_value_pair| {
element_value_pair.* = .{
.element_name_index = try input.takeInt(u16, .big),
.value = try .parse(input, allocator),
};
}
return .{
.target_type = target_type,
.target_info = target_info,
.target_path = target_path,
.type_index = type_index,
.element_value_pairs = element_value_pairs,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
switch (self.target_info) {
.localvar => |localvar| allocator.free(localvar.table),
else => {},
}
for (self.element_value_pairs) |*element_value_pair| {
element_value_pair.value.deinit(allocator);
}
allocator.free(self.element_value_pairs);
}
};
pub const RuntimeVisibleTypeAnnotations = struct {
type_annotations: []TypeAnnotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_annotations = try input.takeInt(u16, .big);
const type_annotations = try allocator.alloc(TypeAnnotation, num_annotations);
errdefer allocator.free(type_annotations);
for (type_annotations) |*type_annotation| {
type_annotation.* = try .parse(input, allocator);
}
return .{
.type_annotations = type_annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.type_annotations) |*type_annotation| {
type_annotation.deinit(allocator);
}
allocator.free(self.type_annotations);
}
};
pub const RuntimeInvisibleTypeAnnotations = struct {
type_annotations: []TypeAnnotation,
const Self = @This();
pub fn parse(input: *std.Io.Reader, allocator: std.mem.Allocator) ParseError!Self {
const num_annotations = try input.takeInt(u16, .big);
const type_annotations = try allocator.alloc(TypeAnnotation, num_annotations);
errdefer allocator.free(type_annotations);
for (type_annotations) |*type_annotation| {
type_annotation.* = try .parse(input, allocator);
}
return .{
.type_annotations = type_annotations,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
for (self.type_annotations) |*type_annotation| {
type_annotation.deinit(allocator);
}
allocator.free(self.type_annotations);
}
};
pub const AnnotationDefault = struct {
default_value: ElementValue,