fix(linter): false positive in no-return-assign (#6128)

This commit is contained in:
DonIsaac 2024-09-27 21:16:50 +00:00
parent ae539af675
commit e7e8eada69
2 changed files with 106 additions and 83 deletions

View file

@ -6,8 +6,10 @@ use serde_json::Value;
use crate::{context::LintContext, rule::Rule, AstNode};
fn no_return_assign_diagnostic(span: Span, message: &str) -> OxcDiagnostic {
OxcDiagnostic::warn(message.to_string()).with_label(span)
fn no_return_assign_diagnostic(span: Span, message: &'static str) -> OxcDiagnostic {
OxcDiagnostic::warn(message)
.with_label(span)
.with_help("Did you mean to use `==` instead of `=`?")
}
#[derive(Debug, Default, Clone)]
@ -39,7 +41,7 @@ declare_oxc_lint!(
/// ```
NoReturnAssign,
style,
suggestion
pending // TODO: add a suggestion
);
fn is_sentinel_node(ast_kind: AstKind) -> bool {
@ -60,35 +62,39 @@ impl Rule for NoReturnAssign {
}
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::AssignmentExpression(_) = node.kind() {
if !self.always_disallow_assignment_in_return
&& ctx
.nodes()
.parent_node(node.id())
.is_some_and(|node| node.kind().as_parenthesized_expression().is_some())
{
return;
}
let mut parent_node = ctx.nodes().parent_node(node.id());
while parent_node.is_some_and(|parent| !is_sentinel_node(parent.kind())) {
parent_node = ctx.nodes().parent_node(parent_node.unwrap().id());
}
if let Some(parent) = parent_node {
match parent.kind() {
AstKind::ReturnStatement(_) => {
ctx.diagnostic(no_return_assign_diagnostic(
parent.span(),
"Return statement should not contain an assignment.",
));
}
AstKind::ArrowFunctionExpression(_) => {
ctx.diagnostic(no_return_assign_diagnostic(
parent.span(),
"Arrow function should not return an assignment.",
));
}
_ => (),
let AstKind::AssignmentExpression(assign) = node.kind() else {
return;
};
if !self.always_disallow_assignment_in_return
&& ctx
.nodes()
.parent_node(node.id())
.is_some_and(|node| node.kind().as_parenthesized_expression().is_some())
{
return;
}
let mut parent_node = ctx.nodes().parent_node(node.id());
while parent_node.is_some_and(|parent| !is_sentinel_node(parent.kind())) {
parent_node = ctx.nodes().parent_node(parent_node.unwrap().id());
}
if let Some(parent) = parent_node {
match parent.kind() {
AstKind::ReturnStatement(_) => {
ctx.diagnostic(no_return_assign_diagnostic(
assign.span(),
"Return statements should not contain an assignment.",
));
}
AstKind::ArrowFunctionExpression(arrow) => {
if arrow.expression {
ctx.diagnostic(no_return_assign_diagnostic(
assign.span(),
"Arrow functions should not return an assignment.",
));
}
}
_ => (),
}
}
}
@ -116,6 +122,7 @@ fn test() {
"function x() { return function y() { result = a * b }; }",
Some(serde_json::json!(["always"])),
),
("() => { a = b; }", None),
("() => { return (result = a * b); }", Some(serde_json::json!(["except-parens"]))),
("() => (result = a * b)", Some(serde_json::json!(["except-parens"]))),
("const foo = (a,b,c) => ((a = b), c)", None),

View file

@ -1,111 +1,127 @@
---
source: crates/oxc_linter/src/tester.rs
---
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:23]
1 │ function x() { return result = a * b; };
· ──────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:23]
1 │ function x() { return (result) = (a * b); };
· ──────────────────────────
· ──────────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:23]
1 │ function x() { return result = a * b; };
· ──────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:23]
1 │ function x() { return (result) = (a * b); };
· ──────────────────────────
· ──────────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:9]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
1 │ () => { return result = a * b; }
· ──────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Arrow function should not return an assignment.
╭─[no_return_assign.tsx:1:1]
⚠ eslint(no-return-assign): Arrow functions should not return an assignment.
╭─[no_return_assign.tsx:1:7]
1 │ () => result = a * b
· ────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:23]
1 │ function x() { return result = a * b; };
· ──────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:24]
1 │ function x() { return (result = a * b); };
· ────────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:1:16]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:1:34]
1 │ function x() { return result || (result = a * b); };
· ──────────────────────────────────
· ──────────────
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:2:20]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:2:27]
1 │ function foo(){
2 │ return a = b
· ────────────
· ─────
3 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:2:20]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:2:27]
1 │ function doSomething() {
2 │ return foo = bar && foo > 0;
· ────────────────────────────
· ────────────────────
3 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:2:20]
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:2:27]
1 │ function doSomething() {
2 │ ╭─▶ return foo = function(){
3 │ │ return (bar = bar1)
4 │ ╰─▶ }
5 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:2:20]
1 │ function doSomething() {
2 │ return foo = () => a
· ────────────────────
3 │ }
╰────
⚠ eslint(no-return-assign): Arrow function should not return an assignment.
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:2:27]
1 │ function doSomething() {
2 │ return () => a = () => b
· ─────────────────
2 │ return foo = () => a
· ─────────────
3 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statement should not contain an assignment.
╭─[no_return_assign.tsx:3:24]
⚠ eslint(no-return-assign): Arrow functions should not return an assignment.
╭─[no_return_assign.tsx:2:33]
1 │ function doSomething() {
2 │ return () => a = () => b
· ───────────
3 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Return statements should not contain an assignment.
╭─[no_return_assign.tsx:3:31]
2 │ return function bar(b){
3 │ return a = b
· ────────────
· ─────
4 │ }
╰────
help: Did you mean to use `==` instead of `=`?
⚠ eslint(no-return-assign): Arrow function should not return an assignment.
╭─[no_return_assign.tsx:1:20]
⚠ eslint(no-return-assign): Arrow functions should not return an assignment.
╭─[no_return_assign.tsx:1:27]
1 │ const foo = (a) => (b) => a = b
· ────────────
· ─────
╰────
help: Did you mean to use `==` instead of `=`?