diff --git a/ast.c b/ast.c index ba2f0eaa00..b98fba6fab 100644 --- a/ast.c +++ b/ast.c @@ -787,7 +787,6 @@ node_locations(VALUE ast_value, const NODE *node) return rb_ary_new_from_args(2, location_new(nd_code_loc(node)), location_new(&RNODE_BLOCK_PASS(node)->operator_loc)); - case NODE_BREAK: return rb_ary_new_from_args(2, location_new(nd_code_loc(node)), @@ -807,6 +806,12 @@ node_locations(VALUE ast_value, const NODE *node) location_new(nd_code_loc(node)), location_new(&RNODE_CASE3(node)->case_keyword_loc), location_new(&RNODE_CASE3(node)->end_keyword_loc)); + case NODE_CLASS: + return rb_ary_new_from_args(4, + location_new(nd_code_loc(node)), + location_new(&RNODE_CLASS(node)->class_keyword_loc), + location_new(&RNODE_CLASS(node)->inheritance_operator_loc), + location_new(&RNODE_CLASS(node)->end_keyword_loc)); case NODE_DOT2: return rb_ary_new_from_args(2, location_new(nd_code_loc(node)), diff --git a/node_dump.c b/node_dump.c index 058aecb960..24711f3d97 100644 --- a/node_dump.c +++ b/node_dump.c @@ -997,8 +997,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) ANN("example: class C2 < C; ..; end"); F_NODE(nd_cpath, RNODE_CLASS, "class path"); F_NODE(nd_super, RNODE_CLASS, "superclass"); - LAST_NODE; F_NODE(nd_body, RNODE_CLASS, "class definition"); + F_LOC(class_keyword_loc, RNODE_CLASS); + F_LOC(inheritance_operator_loc, RNODE_CLASS); + LAST_NODE; + F_LOC(end_keyword_loc, RNODE_CLASS); return; case NODE_MODULE: diff --git a/parse.y b/parse.y index a22ebbbb99..4bca901fc3 100644 --- a/parse.y +++ b/parse.y @@ -1143,7 +1143,7 @@ static rb_node_defs_t *rb_node_defs_new(struct parser_params *p, NODE *nd_recv, static rb_node_alias_t *rb_node_alias_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *keyword_loc); static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc, const YYLTYPE *keyword_loc); static rb_node_undef_t *rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc); -static rb_node_class_t *rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc); +static rb_node_class_t *rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc); static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc); static rb_node_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc); static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc); @@ -1251,7 +1251,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE #define NEW_ALIAS(n,o,loc,k_loc) (NODE *)rb_node_alias_new(p,n,o,loc,k_loc) #define NEW_VALIAS(n,o,loc,k_loc) (NODE *)rb_node_valias_new(p,n,o,loc,k_loc) #define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc) -#define NEW_CLASS(n,b,s,loc) (NODE *)rb_node_class_new(p,n,b,s,loc) +#define NEW_CLASS(n,b,s,loc,ck_loc,io_loc,ek_loc) (NODE *)rb_node_class_new(p,n,b,s,loc,ck_loc,io_loc,ek_loc) #define NEW_MODULE(n,b,loc) (NODE *)rb_node_module_new(p,n,b,loc) #define NEW_SCLASS(r,b,loc) (NODE *)rb_node_sclass_new(p,r,b,loc) #define NEW_COLON2(c,i,loc) (NODE *)rb_node_colon2_new(p,c,i,loc) @@ -4555,7 +4555,12 @@ primary : inline_primary bodystmt k_end { - $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$); + YYLTYPE inheritance_operator_loc = NULL_LOC; + if ($superclass) { + inheritance_operator_loc = @superclass; + inheritance_operator_loc.end_pos.column = inheritance_operator_loc.beg_pos.column + 1; + } + $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$, &@k_class, &inheritance_operator_loc, &@k_end); nd_set_line(RNODE_CLASS($$)->nd_body, @k_end.end_pos.lineno); set_line_body($bodystmt, @superclass.end_pos.lineno); nd_set_line($$, @superclass.end_pos.lineno); @@ -11440,7 +11445,7 @@ rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE * } static rb_node_class_t * -rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc) +rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc) { /* Keep the order of node creation */ NODE *scope = NEW_SCOPE(0, nd_body, loc); @@ -11448,6 +11453,9 @@ rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE * n->nd_cpath = nd_cpath; n->nd_body = scope; n->nd_super = nd_super; + n->class_keyword_loc = *class_keyword_loc; + n->inheritance_operator_loc = *inheritance_operator_loc; + n->end_keyword_loc = *end_keyword_loc; return n; } diff --git a/rubyparser.h b/rubyparser.h index 012c5585cc..16f5cac81f 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -891,6 +891,9 @@ typedef struct RNode_CLASS { struct RNode *nd_cpath; struct RNode *nd_body; struct RNode *nd_super; + rb_code_location_t class_keyword_loc; + rb_code_location_t inheritance_operator_loc; + rb_code_location_t end_keyword_loc; } rb_node_class_t; typedef struct RNode_MODULE { diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index 86676ac577..887dbb6ecf 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1376,6 +1376,14 @@ dummy assert_locations(node.children[-1].locations, [[1, 0, 1, 17], [1, 0, 1, 4], [1, 14, 1, 17]]) end + def test_class_locations + node = ast_parse("class A end") + assert_locations(node.children[-1].locations, [[1, 0, 1, 11], [1, 0, 1, 5], nil, [1, 8, 1, 11]]) + + node = ast_parse("class A < B; end") + assert_locations(node.children[-1].locations, [[1, 0, 1, 16], [1, 0, 1, 5], [1, 8, 1, 9], [1, 13, 1, 16]]) + end + def test_dot2_locations node = ast_parse("1..2") assert_locations(node.children[-1].locations, [[1, 0, 1, 4], [1, 1, 1, 3]])