diff --git a/config.yml b/config.yml index 8a79c19e9..b17f864a7 100644 --- a/config.yml +++ b/config.yml @@ -27,18 +27,21 @@ nodes: - name: old_name - name: location - name: comment + - name: annotations - name: RBS::AST::Declarations::Constant fields: - name: name - name: type - name: location - name: comment + - name: annotations - name: RBS::AST::Declarations::Global fields: - name: name - name: type - name: location - name: comment + - name: annotations - name: RBS::AST::Declarations::Interface fields: - name: name @@ -67,6 +70,7 @@ nodes: - name: old_name - name: location - name: comment + - name: annotations - name: RBS::AST::Declarations::TypeAlias fields: - name: name diff --git a/ext/rbs_extension/parser.c b/ext/rbs_extension/parser.c index fed9a0e83..594df4b7e 100644 --- a/ext/rbs_extension/parser.c +++ b/ext/rbs_extension/parser.c @@ -1314,7 +1314,7 @@ VALUE parse_method_type(parserstate *state) { /* global_decl ::= {tGIDENT} `:` */ -static VALUE parse_global_decl(parserstate *state) { +static VALUE parse_global_decl(parserstate *state, VALUE annotations) { range decl_range; decl_range.start = state->current_token.range.start; @@ -1334,13 +1334,13 @@ static VALUE parse_global_decl(parserstate *state) { rbs_loc_add_required_child(loc, INTERN("name"), name_range); rbs_loc_add_required_child(loc, INTERN("colon"), colon_range); - return rbs_ast_decl_global(typename, type, location, comment); + return rbs_ast_decl_global(typename, type, location, comment, annotations); } /* const_decl ::= {const_name} `:` */ -static VALUE parse_const_decl(parserstate *state) { +static VALUE parse_const_decl(parserstate *state, VALUE annotations) { range decl_range; decl_range.start = state->current_token.range.start; @@ -1361,7 +1361,7 @@ static VALUE parse_const_decl(parserstate *state) { rbs_loc_add_required_child(loc, INTERN("name"), name_range); rbs_loc_add_required_child(loc, INTERN("colon"), colon_range); - return rbs_ast_decl_constant(typename, type, location, comment); + return rbs_ast_decl_constant(typename, type, location, comment, annotations); } /* @@ -2465,7 +2465,7 @@ static VALUE parse_module_decl(parserstate *state, position comment_pos, VALUE a rbs_loc_add_required_child(loc, INTERN("eq"), eq_range); rbs_loc_add_optional_child(loc, INTERN("old_name"), old_name_range); - return rbs_ast_decl_module_alias(module_name, old_name, location, comment); + return rbs_ast_decl_module_alias(module_name, old_name, location, comment, annotations); } else { return parse_module_decl0(state, keyword_range, module_name, module_name_range, comment, annotations); } @@ -2582,7 +2582,7 @@ static VALUE parse_class_decl(parserstate *state, position comment_pos, VALUE an rbs_loc_add_required_child(loc, INTERN("eq"), eq_range); rbs_loc_add_optional_child(loc, INTERN("old_name"), old_name_range); - return rbs_ast_decl_class_alias(class_name, old_name, location, comment); + return rbs_ast_decl_class_alias(class_name, old_name, location, comment, annotations); } else { return parse_class_decl0(state, keyword_range, class_name, class_name_range, comment, annotations); } @@ -2602,11 +2602,11 @@ static VALUE parse_nested_decl(parserstate *state, const char *nested_in, positi switch (state->current_token.type) { case tUIDENT: case pCOLON2: { - decl = parse_const_decl(state); + decl = parse_const_decl(state, annotations); break; } case tGIDENT: { - decl = parse_global_decl(state); + decl = parse_global_decl(state, annotations); break; } case kTYPE: { @@ -2648,10 +2648,10 @@ static VALUE parse_decl(parserstate *state) { switch (state->current_token.type) { case tUIDENT: case pCOLON2: { - return parse_const_decl(state); + return parse_const_decl(state, annotations); } case tGIDENT: { - return parse_global_decl(state); + return parse_global_decl(state, annotations); } case kTYPE: { return parse_type_decl(state, annot_pos, annotations); diff --git a/include/rbs/ruby_objs.h b/include/rbs/ruby_objs.h index 04b2d2466..102e57d40 100644 --- a/include/rbs/ruby_objs.h +++ b/include/rbs/ruby_objs.h @@ -14,13 +14,13 @@ VALUE rbs_ast_annotation(VALUE string, VALUE location); VALUE rbs_ast_comment(VALUE string, VALUE location); VALUE rbs_ast_decl_class(VALUE name, VALUE type_params, VALUE super_class, VALUE members, VALUE annotations, VALUE location, VALUE comment); VALUE rbs_ast_decl_class_super(VALUE name, VALUE args, VALUE location); -VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment); -VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment); -VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment); +VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations); +VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations); +VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations); VALUE rbs_ast_decl_interface(VALUE name, VALUE type_params, VALUE members, VALUE annotations, VALUE location, VALUE comment); VALUE rbs_ast_decl_module(VALUE name, VALUE type_params, VALUE self_types, VALUE members, VALUE annotations, VALUE location, VALUE comment); VALUE rbs_ast_decl_module_self(VALUE name, VALUE args, VALUE location); -VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment); +VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations); VALUE rbs_ast_decl_type_alias(VALUE name, VALUE type_params, VALUE type, VALUE annotations, VALUE location, VALUE comment); VALUE rbs_ast_directives_use(VALUE clauses, VALUE location); VALUE rbs_ast_directives_use_single_clause(VALUE type_name, VALUE new_name, VALUE location); diff --git a/lib/rbs/ast/declarations.rb b/lib/rbs/ast/declarations.rb index bf9f0218f..ba64bf4a5 100644 --- a/lib/rbs/ast/declarations.rb +++ b/lib/rbs/ast/declarations.rb @@ -349,12 +349,14 @@ class Constant < Base attr_reader :type attr_reader :location attr_reader :comment + attr_reader :annotations - def initialize(name:, type:, location:, comment:) + def initialize(name:, type:, location:, comment:, annotations: []) @name = name @type = type @location = location @comment = comment + @annotations = annotations || [] end def ==(other) @@ -385,12 +387,14 @@ class Global < Base attr_reader :type attr_reader :location attr_reader :comment + attr_reader :annotations - def initialize(name:, type:, location:, comment:) + def initialize(name:, type:, location:, comment:, annotations: []) @name = name @type = type @location = location @comment = comment + @annotations = annotations end def ==(other) @@ -417,13 +421,14 @@ def to_json(state = _ = nil) end class AliasDecl < Base - attr_reader :new_name, :old_name, :location, :comment + attr_reader :new_name, :old_name, :location, :comment, :annotations - def initialize(new_name:, old_name:, location:, comment:) + def initialize(new_name:, old_name:, location:, comment:, annotations: []) @new_name = new_name @old_name = old_name @location = location @comment = comment + @annotations = annotations end def ==(other) diff --git a/sig/declarations.rbs b/sig/declarations.rbs index b1a7d9781..1a39f099e 100644 --- a/sig/declarations.rbs +++ b/sig/declarations.rbs @@ -205,8 +205,10 @@ module RBS attr_reader type: Types::t attr_reader location: loc? attr_reader comment: Comment? + attr_reader annotations: Array[Annotation] - def initialize: (name: TypeName, type: Types::t, location: loc?, comment: Comment?) -> void + def initialize: (name: TypeName, type: Types::t, location: loc?, comment: Comment?, annotations: Array[Annotation]) -> void + | %a{deprecated} (name: TypeName, type: Types::t, location: loc?, comment: Comment?) -> void include _HashEqual include _ToJson @@ -223,8 +225,10 @@ module RBS attr_reader type: Types::t attr_reader location: loc? attr_reader comment: Comment? + attr_reader annotations: Array[Annotation] - def initialize: (name: Symbol, type: Types::t, location: loc?, comment: Comment?) -> void + def initialize: (name: Symbol, type: Types::t, location: loc?, comment: Comment?, annotations: Array[Annotation]) -> void + | %a{deprecated} (name: Symbol, type: Types::t, location: loc?, comment: Comment?) -> void include _HashEqual include _ToJson @@ -250,7 +254,10 @@ module RBS attr_reader comment: Comment? - def initialize: (new_name: TypeName, old_name: TypeName, location: loc?, comment: Comment?) -> void + attr_reader annotations: Array[Annotation] + + def initialize: (new_name: TypeName, old_name: TypeName, location: loc?, comment: Comment?, annotations: Array[Annotation]) -> void + | %a{deprecated} (new_name: TypeName, old_name: TypeName, location: loc?, comment: Comment?) -> void include _HashEqual end diff --git a/src/ruby_objs.c b/src/ruby_objs.c index fd9df5429..be3e717f8 100644 --- a/src/ruby_objs.c +++ b/src/ruby_objs.c @@ -71,12 +71,13 @@ VALUE rbs_ast_decl_class_super(VALUE name, VALUE args, VALUE location) { ); } -VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) { +VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations) { VALUE _init_kwargs = rb_hash_new(); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("new_name")), new_name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("old_name")), old_name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment); + rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations); return CLASS_NEW_INSTANCE( RBS_AST_Declarations_ClassAlias, @@ -85,12 +86,13 @@ VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, V ); } -VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment) { +VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations) { VALUE _init_kwargs = rb_hash_new(); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("name")), name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("type")), type); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment); + rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations); return CLASS_NEW_INSTANCE( RBS_AST_Declarations_Constant, @@ -99,12 +101,13 @@ VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE commen ); } -VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment) { +VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations) { VALUE _init_kwargs = rb_hash_new(); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("name")), name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("type")), type); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment); + rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations); return CLASS_NEW_INSTANCE( RBS_AST_Declarations_Global, @@ -159,12 +162,13 @@ VALUE rbs_ast_decl_module_self(VALUE name, VALUE args, VALUE location) { ); } -VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) { +VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations) { VALUE _init_kwargs = rb_hash_new(); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("new_name")), new_name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("old_name")), old_name); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location); rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment); + rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations); return CLASS_NEW_INSTANCE( RBS_AST_Declarations_ModuleAlias, diff --git a/test/rbs/signature_parsing_test.rb b/test/rbs/signature_parsing_test.rb index 49c4f9268..926cee2d3 100644 --- a/test/rbs/signature_parsing_test.rb +++ b/test/rbs/signature_parsing_test.rb @@ -2220,4 +2220,52 @@ module Baz assert_empty dirs end end + + def test_class_module_alias__annotation + Parser.parse_signature(<<~RBS).tap do |_, _, decls| + %a{module} + module Foo = Kernel + + %a{class} class Bar = Object + RBS + + assert_equal 2, decls.size + decls[0].tap do |decl| + assert_instance_of RBS::AST::Declarations::ModuleAlias, decl + assert_equal ["module"], decl.annotations.map(&:string) + end + decls[1].tap do |decl| + assert_instance_of RBS::AST::Declarations::ClassAlias, decl + assert_equal ["class"], decl.annotations.map(&:string) + end + end + end + + def test_global__annotation + Parser.parse_signature(<<~RBS).tap do |_, _, decls| + %a{annotation} + $FOO: String + RBS + + assert_equal 1, decls.size + decls[0].tap do |decl| + assert_instance_of RBS::AST::Declarations::Global, decl + assert_equal ["annotation"], decl.annotations.map(&:string) + end + end + end + + def test_constant__annotation + Parser.parse_signature(<<~RBS).tap do |_, _, decls| + %a{annotation} + FOO: String + RBS + + assert_equal 1, decls.size + decls[0].tap do |decl| + assert_instance_of RBS::AST::Declarations::Constant, decl + assert_equal ["annotation"], decl.annotations.map(&:string) + end + end + end end