summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-05-03 12:51:32 -0400
committergit <svn-admin@ruby-lang.org>2024-05-03 18:09:35 +0000
commit31361aeca3a26eb0fba7269a110870aa259946ae (patch)
tree8515ab279ee6cef55286f3684cbfcf4887ce8d11
parent31c69698a7684e43b4fa6a00629c1ee967fdf458 (diff)
[ruby/prism] Disallow safe navigation in a call target node
https://github.com/ruby/prism/commit/b1917adac7
-rw-r--r--prism/config.yml1
-rw-r--r--prism/prism.c28
-rw-r--r--prism/templates/src/diagnostic.c.erb1
3 files changed, 18 insertions, 12 deletions
diff --git a/prism/config.yml b/prism/config.yml
index 5f1d3b0312..4fc4aa8e6a 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -253,6 +253,7 @@ errors:
- UNEXPECTED_BLOCK_ARGUMENT
- UNEXPECTED_INDEX_BLOCK
- UNEXPECTED_INDEX_KEYWORDS
+ - UNEXPECTED_SAFE_NAVIGATION
- UNEXPECTED_TOKEN_CLOSE_CONTEXT
- UNEXPECTED_TOKEN_IGNORE
- UNTIL_TERM
diff --git a/prism/prism.c b/prism/prism.c
index a9c2a20bb1..c4f3022fe9 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -13034,7 +13034,7 @@ parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) {
* Convert the given node into a valid target node.
*/
static pm_node_t *
-parse_target(pm_parser_t *parser, pm_node_t *target) {
+parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple) {
switch (PM_NODE_TYPE(target)) {
case PM_MISSING_NODE:
return target;
@@ -13102,7 +13102,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
pm_splat_node_t *splat = (pm_splat_node_t *) target;
if (splat->expression != NULL) {
- splat->expression = parse_target(parser, splat->expression);
+ splat->expression = parse_target(parser, splat->expression, multiple);
}
return (pm_node_t *) splat;
@@ -13140,6 +13140,10 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
}
if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
+ if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
+ pm_parser_err_node(parser, (const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
+ }
+
parse_write_name(parser, &call->name);
return (pm_node_t *) pm_call_target_node_create(parser, call);
}
@@ -13167,8 +13171,8 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
* assignment.
*/
static pm_node_t *
-parse_target_validate(pm_parser_t *parser, pm_node_t *target) {
- pm_node_t *result = parse_target(parser, target);
+parse_target_validate(pm_parser_t *parser, pm_node_t *target, bool multiple) {
+ pm_node_t *result = parse_target(parser, target, multiple);
// Ensure that we have one of an =, an 'in' in for indexes, and a ')' in parens after the targets.
if (
@@ -13405,7 +13409,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target));
+ pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target, true));
while (accept1(parser, PM_TOKEN_COMMA)) {
if (accept1(parser, PM_TOKEN_USTAR)) {
@@ -13421,7 +13425,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
if (token_begins_expression_p(parser->current.type)) {
name = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- name = parse_target(parser, name);
+ name = parse_target(parser, name, true);
}
pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
@@ -13429,7 +13433,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
has_rest = true;
} else if (token_begins_expression_p(parser->current.type)) {
pm_node_t *target = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA);
- target = parse_target(parser, target);
+ target = parse_target(parser, target, true);
pm_multi_target_node_targets_append(parser, result, target);
} else if (!match1(parser, PM_TOKEN_EOF)) {
@@ -14450,7 +14454,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
pm_rescue_node_operator_set(rescue, &parser->previous);
pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
+ reference = parse_target(parser, reference, false);
pm_rescue_node_reference_set(rescue, reference);
break;
@@ -14480,7 +14484,7 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, pm_rescues_type
pm_rescue_node_operator_set(rescue, &parser->previous);
pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE);
- reference = parse_target(parser, reference);
+ reference = parse_target(parser, reference, false);
pm_rescue_node_reference_set(rescue, reference);
break;
@@ -17264,7 +17268,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
return (pm_node_t *) multi_target;
}
- return parse_target_validate(parser, (pm_node_t *) multi_target);
+ return parse_target_validate(parser, (pm_node_t *) multi_target, false);
}
// If we have a single statement and are ending on a right parenthesis
@@ -18564,7 +18568,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_COMMA)) {
index = parse_targets(parser, index, PM_BINDING_POWER_INDEX);
} else {
- index = parse_target(parser, index);
+ index = parse_target(parser, index, false);
}
context_pop(parser);
@@ -19351,7 +19355,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
if (match1(parser, PM_TOKEN_COMMA)) {
return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX);
} else {
- return parse_target_validate(parser, splat);
+ return parse_target_validate(parser, splat, false);
}
}
case PM_TOKEN_BANG: {
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index a33ae36f40..86e7c3b6d1 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -335,6 +335,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_UNEXPECTED_BLOCK_ARGUMENT] = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index; blocks are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index; keywords are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNEXPECTED_TOKEN_IGNORE] = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_UNTIL_TERM] = { "expected an `end` to close the `until` statement", PM_ERROR_LEVEL_SYNTAX },