mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(linter/eslint/no-param-reassign): report rest parameter writes (#27765)
Report assignments such as `function f(...args) { args = []; }`, matching ESLint. Rest parameters now use the same reference and property checks as regular parameters, with regression coverage for destructuring, nested scopes, and property-ignore options.
Addresses #27746, report 11 (`eslint/no-param-reassign`).
This commit is contained in:
1 parent
8ea47bbdb5
commit
d85923f968
4 files changed
+145
-6
No files matched your search
+4
-2
@@ -933,8 +933,10 @@ impl RuleRunner for crate::rules::eslint::no_object_constructor::NoObjectConstru
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::eslint::no_param_reassign::NoParamReassign {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> =
|
||||
Some(&AstTypesBitset::from_types(&[AstType::FormalParameter]));
|
||||
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
|
||||
AstType::FormalParameter,
|
||||
AstType::FormalParameterRest,
|
||||
]));
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,12 +92,14 @@ impl Rule for NoParamReassign {
|
||||
}
|
||||
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let AstKind::FormalParameter(param) = node.kind() else {
|
||||
return;
|
||||
let pattern = match node.kind() {
|
||||
AstKind::FormalParameter(param) => ¶m.pattern,
|
||||
AstKind::FormalParameterRest(param) => ¶m.rest.argument,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let symbol_table = ctx.scoping();
|
||||
param.pattern.bound_names(&mut |ident| {
|
||||
pattern.bound_names(&mut |ident| {
|
||||
let symbol_id = ident.symbol_id();
|
||||
|
||||
let declaration_id = symbol_table.symbol_declaration(symbol_id);
|
||||
@@ -256,6 +258,25 @@ fn test() {
|
||||
"function foo<T>(this: Record<PropertyKey, T>, key: PropertyKey, value: T) { this[key] = value; }",
|
||||
Some(serde_json::json!([{ "props": true }])),
|
||||
),
|
||||
("function f(...args) { return args.reverse(); }", None),
|
||||
("function f(...args) { args[0] = 1; }", None),
|
||||
(
|
||||
"function f(...args) { args[0] = 1; }",
|
||||
Some(
|
||||
serde_json::json!([{ "props": true, "ignorePropertyModificationsFor": ["args"] }]),
|
||||
),
|
||||
),
|
||||
(
|
||||
"function f(...args) { delete args[0]; }",
|
||||
Some(
|
||||
serde_json::json!([{ "props": true, "ignorePropertyModificationsForRegex": ["^arg"] }]),
|
||||
),
|
||||
),
|
||||
(
|
||||
"function f(...args) { function g() { let args; args = []; } return args; }",
|
||||
Some(serde_json::json!([{ "props": true }])),
|
||||
),
|
||||
("const [...args] = []; args = [];", Some(serde_json::json!([{ "props": true }]))),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
@@ -333,6 +354,29 @@ fn test() {
|
||||
("function foo(a) { a.b &&= c; }", Some(serde_json::json!([{ "props": true }]))), // { "ecmaVersion": 2021 },
|
||||
("function foo(a) { a.b.c ||= d; }", Some(serde_json::json!([{ "props": true }]))), // { "ecmaVersion": 2021 },
|
||||
("function foo(a) { a[b] ??= c; }", Some(serde_json::json!([{ "props": true }]))), // { "ecmaVersion": 2021 }
|
||||
(
|
||||
"export function f(...args) { args = args.reverse(); return args; }
|
||||
export function g(x) { x = 1; return x; }",
|
||||
None,
|
||||
),
|
||||
("const f = (...args) => args = [];", None),
|
||||
("const f = function(...args) { args++; };", None),
|
||||
("const obj = { f(...args) { args = []; } };", None),
|
||||
("class C { f(...args) { args = []; } }", None),
|
||||
("function f(...[arg]) { arg = 1; }", None),
|
||||
("function f(...{length}) { length = 0; }", None),
|
||||
(
|
||||
"function f(...args) { args[0] = 1; delete args[1]; }",
|
||||
Some(serde_json::json!([{ "props": true }])),
|
||||
),
|
||||
(
|
||||
"function f(...args) { args = []; }",
|
||||
Some(
|
||||
serde_json::json!([{ "props": true, "ignorePropertyModificationsFor": ["args"] }]),
|
||||
),
|
||||
),
|
||||
("function f({a, ...args}) { args = {}; }", None),
|
||||
("function f(...args) { function g() { args = []; } }", None),
|
||||
];
|
||||
|
||||
Tester::new(NoParamReassign::NAME, NoParamReassign::PLUGIN, pass, fail).test_and_snapshot();
|
||||
|
||||
@@ -344,3 +344,96 @@ source: crates/oxc_linter/src/tester.rs
|
||||
· ─
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter's properties.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:30]
|
||||
1 │ export function f(...args) { args = args.reverse(); return args; }
|
||||
· ────
|
||||
2 │ export function g(x) { x = 1; return x; }
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'x'.
|
||||
╭─[no_param_reassign.tsx:2:37]
|
||||
1 │ export function f(...args) { args = args.reverse(); return args; }
|
||||
2 │ export function g(x) { x = 1; return x; }
|
||||
· ─
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:24]
|
||||
1 │ const f = (...args) => args = [];
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:31]
|
||||
1 │ const f = function(...args) { args++; };
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:28]
|
||||
1 │ const obj = { f(...args) { args = []; } };
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:24]
|
||||
1 │ class C { f(...args) { args = []; } }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'arg'.
|
||||
╭─[no_param_reassign.tsx:1:24]
|
||||
1 │ function f(...[arg]) { arg = 1; }
|
||||
· ───
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'length'.
|
||||
╭─[no_param_reassign.tsx:1:27]
|
||||
1 │ function f(...{length}) { length = 0; }
|
||||
· ──────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to property of function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:23]
|
||||
1 │ function f(...args) { args[0] = 1; delete args[1]; }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter's properties.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to property of function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:43]
|
||||
1 │ function f(...args) { args[0] = 1; delete args[1]; }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter's properties.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:23]
|
||||
1 │ function f(...args) { args = []; }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:28]
|
||||
1 │ function f({a, ...args}) { args = {}; }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
|
||||
⚠ eslint(no-param-reassign): Assignment to function parameter 'args'.
|
||||
╭─[no_param_reassign.tsx:1:38]
|
||||
1 │ function f(...args) { function g() { args = []; } }
|
||||
· ────
|
||||
╰────
|
||||
help: Consider using a different variable to avoid unintended side effects on the parameter.
|
||||
@@ -100,7 +100,7 @@ eslint/no-new-wrappers | 1421
|
||||
eslint/no-nonoctal-decimal-escape | 62460
|
||||
eslint/no-obj-calls | 64027
|
||||
eslint/no-object-constructor | 64027
|
||||
eslint/no-param-reassign | 24806
|
||||
eslint/no-param-reassign | 24902
|
||||
eslint/no-plusplus | 769
|
||||
eslint/no-promise-executor-return | 1421
|
||||
eslint/no-proto | 95297
|
||||
|
||||
Reference in new issue
Block a user