summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-04-12 10:49:30 -0400
committergit <svn-admin@ruby-lang.org>2024-04-12 14:58:03 +0000
commitc41ecf3f470ab5a4cba410743dc8154694f9d885 (patch)
treeb8c9de85834f8cd991e8c175a72ef07dd201de12
parentc553d3483542f933df41a71f1ad8f5bcb1142c2b (diff)
[ruby/prism] Create the warning for unreachable statements
https://github.com/ruby/prism/commit/e17c86b886
-rw-r--r--prism/config.yml1
-rw-r--r--prism/prism.c47
-rw-r--r--prism/templates/src/diagnostic.c.erb1
-rw-r--r--test/prism/warnings_test.rb14
4 files changed, 48 insertions, 15 deletions
diff --git a/prism/config.yml b/prism/config.yml
index 889ceccbf4..17fff0431a 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -269,6 +269,7 @@ warnings:
- LITERAL_IN_CONDITION_VERBOSE
- SHEBANG_CARRIAGE_RETURN
- UNEXPECTED_CARRIAGE_RETURN
+ - UNREACHABLE_STATEMENT
- UNUSED_LOCAL_VARIABLE
- VOID_STATEMENT
tokens:
diff --git a/prism/prism.c b/prism/prism.c
index 694efddb2f..c370a8b2bf 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -1895,7 +1895,7 @@ static pm_statements_node_t *
pm_statements_node_create(pm_parser_t *parser);
static void
-pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement);
+pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement);
static size_t
pm_statements_node_body_length(pm_statements_node_t *node);
@@ -4554,7 +4554,7 @@ pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_t
pm_if_node_t *node = PM_ALLOC_NODE(parser, pm_if_node_t);
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
+ pm_statements_node_body_append(parser, statements, statement);
*node = (pm_if_node_t) {
{
@@ -4585,10 +4585,10 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_to
pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
pm_statements_node_t *if_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(if_statements, true_expression);
+ pm_statements_node_body_append(parser, if_statements, true_expression);
pm_statements_node_t *else_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(else_statements, false_expression);
+ pm_statements_node_body_append(parser, else_statements, false_expression);
pm_token_t end_keyword = not_provided(parser);
pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
@@ -6609,8 +6609,25 @@ pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement)
* Append a new node to the given StatementsNode node's body.
*/
static void
-pm_statements_node_body_append(pm_statements_node_t *node, pm_node_t *statement) {
+pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement) {
pm_statements_node_body_update(node, statement);
+
+ if (node->body.size > 0) {
+ const pm_node_t *previous = node->body.nodes[node->body.size - 1];
+
+ switch (PM_NODE_TYPE(previous)) {
+ case PM_BREAK_NODE:
+ case PM_NEXT_NODE:
+ case PM_REDO_NODE:
+ case PM_RETRY_NODE:
+ case PM_RETURN_NODE:
+ pm_parser_warn_node(parser, previous, PM_WARN_UNREACHABLE_STATEMENT);
+ break;
+ default:
+ break;
+ }
+ }
+
pm_node_list_append(&node->body, statement);
pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
}
@@ -7173,7 +7190,7 @@ pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const
pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
+ pm_statements_node_body_append(parser, statements, statement);
*node = (pm_unless_node_t) {
{
@@ -13007,7 +13024,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
while (true) {
pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
- pm_statements_node_body_append(statements, node);
+ pm_statements_node_body_append(parser, statements, node);
// If we're recovering from a syntax error, then we need to stop parsing the
// statements now.
@@ -16762,7 +16779,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// and we didn't return a multiple assignment node, then we can return a
// regular parentheses node now.
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
+ pm_statements_node_body_append(parser, statements, statement);
return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
}
@@ -16772,7 +16789,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// We'll do that here.
context_push(parser, PM_CONTEXT_PARENS);
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, statement);
+ pm_statements_node_body_append(parser, statements, statement);
// If we didn't find a terminator and we didn't find a right
// parenthesis, then this is a syntax error.
@@ -16783,7 +16800,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
// Parse each statement within the parentheses.
while (true) {
pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
- pm_statements_node_body_append(statements, node);
+ pm_statements_node_body_append(parser, statements, node);
// If we're recovering from a syntax error, then we need to stop
// parsing the statements now.
@@ -17893,7 +17910,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
}
- pm_statements_node_body_append((pm_statements_node_t *) statements, statement);
+ pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement);
pm_do_loop_stack_pop(parser);
context_pop(parser);
end_keyword = not_provided(parser);
@@ -19864,7 +19881,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
parser_lex(parser);
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, node);
+ pm_statements_node_body_append(parser, statements, node);
pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
@@ -19872,7 +19889,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
parser_lex(parser);
pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(statements, node);
+ pm_statements_node_body_append(parser, statements, node);
pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
@@ -20217,7 +20234,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
(pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2))
);
- pm_statements_node_body_append(statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
+ pm_statements_node_body_append(parser, statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
parser,
arguments,
pm_parser_constant_id_constant(parser, "print", 5)
@@ -20263,7 +20280,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
}
pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
+ pm_statements_node_body_append(parser, wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
parser,
(pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4)),
statements
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index 5044a69c2b..209afd2ee5 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -352,6 +352,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_WARN_LITERAL_IN_CONDITION_VERBOSE] = { "%sliteral in %s", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_SHEBANG_CARRIAGE_RETURN] = { "shebang line ending with \\r may cause problems", PM_WARNING_LEVEL_DEFAULT },
[PM_WARN_UNEXPECTED_CARRIAGE_RETURN] = { "encountered \\r in middle of line, treated as a mere space", PM_WARNING_LEVEL_DEFAULT },
+ [PM_WARN_UNREACHABLE_STATEMENT] = { "statement not reached", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_UNUSED_LOCAL_VARIABLE] = { "assigned but unused variable - %.*s", PM_WARNING_LEVEL_VERBOSE },
[PM_WARN_VOID_STATEMENT] = { "possibly useless use of %.*s in void context", PM_WARNING_LEVEL_VERBOSE }
};
diff --git a/test/prism/warnings_test.rb b/test/prism/warnings_test.rb
index ff9c306c99..7eb1bbd2e1 100644
--- a/test/prism/warnings_test.rb
+++ b/test/prism/warnings_test.rb
@@ -187,6 +187,20 @@ module Prism
refute_warning("@foo", compare: false, scopes: [[]])
end
+ def test_unreachable_statement
+ assert_warning("begin; rescue; retry; foo; end", "statement not reached")
+
+ assert_warning("return; foo", "statement not reached")
+
+ assert_warning("tap { break; foo }", "statement not reached")
+ assert_warning("tap { break 1; foo }", "statement not reached")
+
+ assert_warning("tap { next; foo }", "statement not reached")
+ assert_warning("tap { next 1; foo }", "statement not reached")
+
+ assert_warning("tap { redo; foo }", "statement not reached")
+ end
+
private
def assert_warning(source, message)