-
-
Notifications
You must be signed in to change notification settings - Fork 192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#265 Warn on redundant semicolon after else #290
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# E204: semicolon after else may be causing unexpected behavior. | ||
|
||
A semicolon next to the `else` keyword may cause its body to be executed even when previous `if` statement condition is true. | ||
|
||
if (true) { | ||
console.log("true"); | ||
} else; { | ||
console.log("else"); | ||
} | ||
|
||
Example output | ||
``` | ||
> true | ||
> else | ||
``` | ||
|
||
To avoid this behavior, remove the semicolon between the else keyword and the opening brace of the else block. | ||
|
||
if (true) { | ||
console.log("true"); | ||
} else { | ||
console.log("else"); | ||
} | ||
|
||
Or if the else body is not required remove it completely. | ||
|
||
if (true) { | ||
console.log("true"); | ||
} | ||
console.log("always"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lovely docs! |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -578,6 +578,44 @@ TEST(test_parse, else_without_if) { | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
TEST(test_parse, else_unexpected_semicolon) { | ||||||||||
{ | ||||||||||
spy_visitor v; | ||||||||||
padded_string code(u8"if (cond) { body; } else; { body; }"_sv); | ||||||||||
parser p(&code, &v); | ||||||||||
EXPECT_TRUE(p.parse_and_visit_statement(v)); | ||||||||||
EXPECT_THAT(v.visits, ElementsAre("visit_variable_use", // cond | ||||||||||
"visit_enter_block_scope", // (if) | ||||||||||
"visit_variable_use", // body | ||||||||||
"visit_exit_block_scope")); // (if) | ||||||||||
|
||||||||||
EXPECT_THAT(v.errors, | ||||||||||
ElementsAre(ERROR_TYPE_FIELD( | ||||||||||
error_unexpected_semicolon_after_else, semicolon, | ||||||||||
offsets_matcher(&code, strlen(u8"if (cond) { body; } else"), | ||||||||||
u8";")))); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
TEST(test_parse, else_has_empty_body) { | ||||||||||
{ | ||||||||||
spy_visitor v; | ||||||||||
padded_string code(u8"if (cond) { body; } else;\n{ }"_sv); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I don't think it's worth having a diagnostic for this code. If there's a newline after the |
||||||||||
parser p(&code, &v); | ||||||||||
EXPECT_TRUE(p.parse_and_visit_statement(v)); | ||||||||||
EXPECT_THAT(v.visits, ElementsAre("visit_variable_use", // cond | ||||||||||
"visit_enter_block_scope", // (if) | ||||||||||
"visit_variable_use", // body | ||||||||||
"visit_exit_block_scope")); // (if) | ||||||||||
EXPECT_THAT( | ||||||||||
v.errors, | ||||||||||
ElementsAre(ERROR_TYPE_FIELD( | ||||||||||
error_else_has_empty_body, where, | ||||||||||
offsets_matcher(&code, strlen(u8"if (cond) { body; } else {"), | ||||||||||
u8"}")))); | ||||||||||
Comment on lines
+614
to
+615
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocking: This strlen string doesn't match the code. The
Suggested change
If so, the error looks misplaced. It should point at the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now it detects - if (token_after_else.type == token_type::semicolon &&
- this->peek().type == token_type::left_curly) {
+ if (token_after_else.type == token_type::semicolon &&
+ this->peek().type == token_type::left_curly &&
+ !this->peek().has_leading_newline) {
- if (this->peek().has_leading_newline) {
+ if (body is empty) {
this->error_reporter_->report(
error_else_has_empty_body{.where = this->peek().span()});
} else {
this->error_reporter_->report(error_unexpected_semicolon_after_else{
.semicolon = token_after_else.span()});
}
} Should I omit the else has empty body warning altogether, or should I detect the empty body? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, let's only emit error_unexpected_semicolon_after_else in this PR.
Would something like this work? Or am I missing an edge case? if (token_after_else.type == token_type::semicolon &&
this->peek().type == token_type::left_curly &&
!this->peek().has_leading_newline) {
this->error_reporter_->report(error_unexpected_semicolon_after_else{
.semicolon = token_after_else.span(),
});
} |
||||||||||
} | ||||||||||
} | ||||||||||
someoneigna marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
TEST(test_parse, block_statement) { | ||||||||||
{ | ||||||||||
spy_visitor v = parse_and_visit_statement(u8"{ }"_sv); | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone else took error code E204. Choose a different error code.