mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 09:38:16 +03:00
feat(es/lints): Implement no-param-reassign
rule (#4134)
This commit is contained in:
parent
a293adca0a
commit
47712de0da
@ -0,0 +1,14 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"no-param-reassign": [
|
||||
"error",
|
||||
{
|
||||
"ignorePropertyModificationsForRegex": [
|
||||
"^ignore"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
function f(ignoreMe, catchMe) {
|
||||
ignoreMe = 1;
|
||||
catchMe = 1;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
|
||||
x Assignment to function parameter 'catchMe'
|
||||
,----
|
||||
3 | catchMe = 1;
|
||||
: ^^^^^^^
|
||||
`----
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"no-param-reassign": [
|
||||
"error",
|
||||
{
|
||||
"ignorePropertyModificationsFor": [
|
||||
"b"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
function f(a, b) {
|
||||
a = 1;
|
||||
b = 1;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
2 | a = 1;
|
||||
: ^
|
||||
`----
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"no-param-reassign": [
|
||||
"error",
|
||||
{
|
||||
"props": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
function f(a) {
|
||||
a = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
function f3() {
|
||||
a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
a.prop = 1;
|
||||
(a).prop = 1;
|
||||
(((((((a))))))).prop = 1;
|
||||
(void 0, a).prop = 1;
|
||||
(a.prop = 1);
|
||||
(void 0, a.prop = 1, void 0)
|
||||
a.prop.b = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
a++;
|
||||
++a;
|
||||
a.prop++;
|
||||
++a.prop;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
for (a of []) {}
|
||||
for (const a of []) {}
|
||||
|
||||
for (a in []) {}
|
||||
for (const a in []) {}
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
delete a.x;
|
||||
}
|
||||
|
||||
function f(a, b, c) {
|
||||
({ a } = {});
|
||||
({ a, b } = {});
|
||||
({ a, b, k: { c } } = {});
|
||||
([a] = []);
|
||||
([{a}, [b]] = [])
|
||||
}
|
||||
|
||||
function f(a, { b, k: { c }, k2: [ d ] }, [e, [f], { g }]) {
|
||||
a = 1;
|
||||
b = 1;
|
||||
c = 1;
|
||||
d = 1;
|
||||
e = 1;
|
||||
f = 1;
|
||||
g = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
alert(a);
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
2 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
7 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
22 | a++;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
23 | ++a;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
29 | for (a of []) {}
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
32 | for (a in []) {}
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
41 | ({ a } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
42 | ({ a, b } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
42 | ({ a, b } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'c'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
44 | ([a] = []);
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
45 | ([{a}, [b]] = [])
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
45 | ([{a}, [b]] = [])
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
49 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
50 | b = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'c'
|
||||
,----
|
||||
51 | c = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'd'
|
||||
,----
|
||||
52 | d = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'e'
|
||||
,----
|
||||
53 | e = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'f'
|
||||
,----
|
||||
54 | f = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'g'
|
||||
,----
|
||||
55 | g = 1;
|
||||
: ^
|
||||
`----
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"jsc": {
|
||||
"lints": {
|
||||
"no-param-reassign": [
|
||||
"error"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
function f(a) {
|
||||
a = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
function f3() {
|
||||
a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
a.prop = 1;
|
||||
(a).prop = 1;
|
||||
(((((((a))))))).prop = 1;
|
||||
(void 0, a).prop = 1;
|
||||
(a.prop = 1);
|
||||
(void 0, a.prop = 1, void 0)
|
||||
a.prop.b = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
a++;
|
||||
++a;
|
||||
a.prop++;
|
||||
++a.prop;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
for (a of []) {}
|
||||
for (const a of []) {}
|
||||
|
||||
for (a in []) {}
|
||||
for (const a in []) {}
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
delete a.x;
|
||||
}
|
||||
|
||||
function f(a, b, c) {
|
||||
({ a } = {});
|
||||
({ a, b } = {});
|
||||
({ a, b, k: { c } } = {});
|
||||
([a] = []);
|
||||
([{a}, [b]] = [])
|
||||
}
|
||||
|
||||
function f(a, { b, k: { c }, k2: [ d ] }, [e, [f], { g }]) {
|
||||
a = 1;
|
||||
b = 1;
|
||||
c = 1;
|
||||
d = 1;
|
||||
e = 1;
|
||||
f = 1;
|
||||
g = 1;
|
||||
}
|
||||
|
||||
function f(a) {
|
||||
alert(a);
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
2 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
7 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
12 | a.prop = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
13 | (a).prop = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
14 | (((((((a))))))).prop = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
15 | (void 0, a).prop = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
16 | (a.prop = 1);
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
17 | (void 0, a.prop = 1, void 0)
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
18 | a.prop.b = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
22 | a++;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
23 | ++a;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
24 | a.prop++;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
25 | ++a.prop;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
29 | for (a of []) {}
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
32 | for (a in []) {}
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
37 | delete a.x;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
41 | ({ a } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
42 | ({ a, b } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
42 | ({ a, b } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'c'
|
||||
,----
|
||||
43 | ({ a, b, k: { c } } = {});
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
44 | ([a] = []);
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
45 | ([{a}, [b]] = [])
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
45 | ([{a}, [b]] = [])
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'a'
|
||||
,----
|
||||
49 | a = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'b'
|
||||
,----
|
||||
50 | b = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'c'
|
||||
,----
|
||||
51 | c = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'd'
|
||||
,----
|
||||
52 | d = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'e'
|
||||
,----
|
||||
53 | e = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'f'
|
||||
,----
|
||||
54 | f = 1;
|
||||
: ^
|
||||
`----
|
||||
|
||||
x Assignment to function parameter 'g'
|
||||
,----
|
||||
55 | g = 1;
|
||||
: ^
|
||||
`----
|
@ -6,7 +6,8 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::rules::non_critical_lints::{
|
||||
dot_notation::DotNotationConfig, eqeqeq::EqeqeqConfig, no_bitwise::NoBitwiseConfig,
|
||||
no_console::NoConsoleConfig, no_empty_function::NoEmptyFunctionConfig,
|
||||
no_restricted_syntax::NoRestrictedSyntaxConfig, no_use_before_define::NoUseBeforeDefineConfig,
|
||||
no_param_reassign::NoParamReassignConfig, no_restricted_syntax::NoRestrictedSyntaxConfig,
|
||||
no_use_before_define::NoUseBeforeDefineConfig,
|
||||
prefer_regex_literals::PreferRegexLiteralsConfig, quotes::QuotesConfig, radix::RadixConfig,
|
||||
use_is_nan::UseIsNanConfig, valid_typeof::ValidTypeofConfig, yoda::YodaConfig,
|
||||
};
|
||||
@ -150,4 +151,8 @@ pub struct LintConfig {
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default, alias = "validTypeof")]
|
||||
pub valid_typeof: RuleConfig<ValidTypeofConfig>,
|
||||
|
||||
#[cfg(feature = "non_critical_lints")]
|
||||
#[serde(default, alias = "noParamReassign")]
|
||||
pub no_param_reassign: RuleConfig<NoParamReassignConfig>,
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ pub(crate) mod non_critical_lints {
|
||||
pub mod no_loop_func;
|
||||
pub mod no_new;
|
||||
pub mod no_new_symbol;
|
||||
pub mod no_param_reassign;
|
||||
pub mod no_restricted_syntax;
|
||||
pub mod no_use_before_define;
|
||||
pub mod prefer_regex_literals;
|
||||
@ -146,6 +147,10 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
|
||||
));
|
||||
|
||||
rules.extend(valid_typeof::valid_typeof(&lint_config.valid_typeof));
|
||||
|
||||
rules.extend(no_param_reassign::no_param_reassign(
|
||||
&lint_config.no_param_reassign,
|
||||
));
|
||||
}
|
||||
|
||||
rules
|
||||
|
281
crates/swc_ecma_lints/src/rules/no_param_reassign.rs
Normal file
281
crates/swc_ecma_lints/src/rules/no_param_reassign.rs
Normal file
@ -0,0 +1,281 @@
|
||||
use dashmap::DashMap;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use swc_common::{
|
||||
collections::{AHashMap, AHashSet},
|
||||
errors::HANDLER,
|
||||
sync::Lazy,
|
||||
Span,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::ident::IdentLike;
|
||||
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
|
||||
|
||||
use crate::{
|
||||
config::{LintRuleReaction, RuleConfig},
|
||||
rule::{visitor_rule, Rule},
|
||||
rules::utils::unwrap_seqs_and_parens,
|
||||
};
|
||||
|
||||
const INVALID_REGEX_MESSAGE: &str = "no-param-reassign: invalid regex pattern in allowPattern. Check syntax documentation https://docs.rs/regex/latest/regex/#syntax";
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NoParamReassignConfig {
|
||||
props: Option<bool>,
|
||||
ignore_property_modifications_for: Option<AHashSet<String>>,
|
||||
ignore_property_modifications_for_regex: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub fn no_param_reassign(config: &RuleConfig<NoParamReassignConfig>) -> Option<Box<dyn Rule>> {
|
||||
match config.get_rule_reaction() {
|
||||
LintRuleReaction::Off => None,
|
||||
_ => Some(visitor_rule(NoParamReassign::new(config))),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct NoParamReassign {
|
||||
expected_reaction: LintRuleReaction,
|
||||
scoped_params: AHashMap<Span, AHashSet<Id>>,
|
||||
scopes: Vec<Span>,
|
||||
check_props: bool,
|
||||
ignore_names: Option<AHashSet<String>>,
|
||||
ignore_names_patterns: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl NoParamReassign {
|
||||
fn new(config: &RuleConfig<NoParamReassignConfig>) -> Self {
|
||||
let rule_config = config.get_rule_config();
|
||||
|
||||
Self {
|
||||
expected_reaction: config.get_rule_reaction(),
|
||||
scoped_params: Default::default(),
|
||||
scopes: vec![],
|
||||
check_props: rule_config.props.unwrap_or(true),
|
||||
ignore_names: rule_config.ignore_property_modifications_for.clone(),
|
||||
ignore_names_patterns: rule_config.ignore_property_modifications_for_regex.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_report(&self, span: Span, name: &str) {
|
||||
let message = format!("Assignment to function parameter '{}'", name);
|
||||
|
||||
HANDLER.with(|handler| match self.expected_reaction {
|
||||
LintRuleReaction::Error => {
|
||||
handler.struct_span_err(span, &message).emit();
|
||||
}
|
||||
LintRuleReaction::Warning => {
|
||||
handler.struct_span_warn(span, &message).emit();
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
fn collect_function_params(&mut self, pat: &Pat) {
|
||||
match pat {
|
||||
Pat::Ident(BindingIdent { id, .. }) => {
|
||||
self.scoped_params
|
||||
.get_mut(self.scopes.last().unwrap())
|
||||
.unwrap()
|
||||
.insert(id.to_id());
|
||||
}
|
||||
Pat::Object(ObjectPat { props, .. }) => props.iter().for_each(|prop| {
|
||||
match prop {
|
||||
ObjectPatProp::Assign(AssignPatProp { key, .. }) => {
|
||||
self.scoped_params
|
||||
.get_mut(self.scopes.last().unwrap())
|
||||
.unwrap()
|
||||
.insert(key.to_id());
|
||||
}
|
||||
ObjectPatProp::KeyValue(KeyValuePatProp { value, .. }) => {
|
||||
self.collect_function_params(value.as_ref());
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}),
|
||||
Pat::Array(ArrayPat { elems, .. }) => elems.iter().for_each(|elem| {
|
||||
if let Some(elem) = elem {
|
||||
self.collect_function_params(elem);
|
||||
}
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_satisfying_function_param(&self, ident: &Ident) -> bool {
|
||||
if let Some(ignore_names) = &self.ignore_names {
|
||||
if ignore_names.contains(&*ident.sym) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let is_function_param = self.scopes.iter().rev().any(|scope| {
|
||||
self.scoped_params
|
||||
.get(scope)
|
||||
.unwrap()
|
||||
.contains(&ident.to_id())
|
||||
});
|
||||
|
||||
if !is_function_param {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(ignore_names_patterns) = &self.ignore_names_patterns {
|
||||
static REGEX_CACHE: Lazy<DashMap<String, Regex, ahash::RandomState>> =
|
||||
Lazy::new(Default::default);
|
||||
|
||||
let sym = &*ident.sym;
|
||||
|
||||
let ignored_by_pattern = ignore_names_patterns.iter().any(|pattern| {
|
||||
if !REGEX_CACHE.contains_key(pattern) {
|
||||
REGEX_CACHE.insert(
|
||||
pattern.clone(),
|
||||
Regex::new(pattern).expect(INVALID_REGEX_MESSAGE),
|
||||
);
|
||||
}
|
||||
|
||||
return REGEX_CACHE.get(pattern).unwrap().is_match(sym);
|
||||
});
|
||||
|
||||
if ignored_by_pattern {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn check_obj_member(&self, member_expr: &MemberExpr) {
|
||||
if !self.check_props {
|
||||
return;
|
||||
}
|
||||
|
||||
match unwrap_seqs_and_parens(member_expr.obj.as_ref()) {
|
||||
Expr::Ident(ident) => {
|
||||
if self.is_satisfying_function_param(ident) {
|
||||
self.emit_report(ident.span, &ident.sym);
|
||||
}
|
||||
}
|
||||
Expr::Member(member_expr) => {
|
||||
self.check_obj_member(member_expr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat_or_expr(&self, pat_or_expr: &PatOrExpr) {
|
||||
match pat_or_expr {
|
||||
PatOrExpr::Pat(pat) => {
|
||||
self.check_pat(pat.as_ref());
|
||||
}
|
||||
PatOrExpr::Expr(expr) => {
|
||||
self.check_expr(expr.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&self, expr: &Expr) {
|
||||
match unwrap_seqs_and_parens(expr) {
|
||||
Expr::Ident(ident) => {
|
||||
if self.is_satisfying_function_param(ident) {
|
||||
self.emit_report(ident.span, &ident.sym);
|
||||
}
|
||||
}
|
||||
Expr::Member(member_expr) => {
|
||||
self.check_obj_member(member_expr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat(&self, pat: &Pat) {
|
||||
match pat {
|
||||
Pat::Ident(BindingIdent { id, .. }) => {
|
||||
if self.is_satisfying_function_param(id) {
|
||||
self.emit_report(id.span, &id.sym);
|
||||
}
|
||||
}
|
||||
Pat::Expr(expr) => {
|
||||
if let Expr::Member(member_expr) = expr.as_ref() {
|
||||
self.check_obj_member(member_expr);
|
||||
}
|
||||
}
|
||||
Pat::Object(ObjectPat { props, .. }) => {
|
||||
props.iter().for_each(|prop| match prop {
|
||||
ObjectPatProp::Assign(AssignPatProp { key, .. }) => {
|
||||
if self.is_satisfying_function_param(key) {
|
||||
self.emit_report(key.span, &key.sym);
|
||||
}
|
||||
}
|
||||
ObjectPatProp::KeyValue(KeyValuePatProp { value, .. }) => {
|
||||
self.check_pat(value.as_ref());
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
Pat::Array(ArrayPat { elems, .. }) => {
|
||||
elems.iter().for_each(|elem| {
|
||||
if let Some(elem) = elem {
|
||||
self.check_pat(elem);
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for NoParamReassign {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_function(&mut self, function: &Function) {
|
||||
self.scopes.push(function.span);
|
||||
self.scoped_params.insert(function.span, Default::default());
|
||||
|
||||
function.params.iter().for_each(|param| {
|
||||
self.collect_function_params(¶m.pat);
|
||||
});
|
||||
|
||||
function.visit_children_with(self);
|
||||
|
||||
self.scopes.pop();
|
||||
self.scoped_params.remove(&function.span);
|
||||
}
|
||||
|
||||
fn visit_assign_expr(&mut self, assign_expr: &AssignExpr) {
|
||||
self.check_pat_or_expr(&assign_expr.left);
|
||||
|
||||
assign_expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_update_expr(&mut self, update_expr: &UpdateExpr) {
|
||||
self.check_expr(update_expr.arg.as_ref());
|
||||
|
||||
update_expr.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_for_of_stmt(&mut self, for_of_stmt: &ForOfStmt) {
|
||||
if let VarDeclOrPat::Pat(pat) = &for_of_stmt.left {
|
||||
self.check_pat(pat);
|
||||
}
|
||||
|
||||
for_of_stmt.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_for_in_stmt(&mut self, for_in_stmt: &ForInStmt) {
|
||||
if let VarDeclOrPat::Pat(pat) = &for_in_stmt.left {
|
||||
self.check_pat(pat);
|
||||
}
|
||||
|
||||
for_in_stmt.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_unary_expr(&mut self, unary_expr: &UnaryExpr) {
|
||||
if let op!("delete") = unary_expr.op {
|
||||
self.check_expr(unary_expr.arg.as_ref());
|
||||
}
|
||||
|
||||
unary_expr.visit_children_with(self);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{collections::AHashSet, SourceMap, Span, SyntaxContext};
|
||||
use swc_ecma_ast::{
|
||||
Expr, Id, Lit, MemberExpr, MemberProp, Number, ParenExpr, Regex, Str, TaggedTpl, Tpl,
|
||||
Expr, Id, Lit, MemberExpr, MemberProp, Number, ParenExpr, Regex, SeqExpr, Str, TaggedTpl, Tpl,
|
||||
};
|
||||
use swc_ecma_utils::ident::IdentLike;
|
||||
|
||||
@ -131,3 +131,11 @@ pub fn extract_arg_val(
|
||||
_ => ArgValue::Other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_seqs_and_parens(expr: &Expr) -> &Expr {
|
||||
match expr {
|
||||
Expr::Seq(SeqExpr { exprs, .. }) => unwrap_seqs_and_parens(exprs.last().unwrap()),
|
||||
Expr::Paren(ParenExpr { expr, .. }) => unwrap_seqs_and_parens(expr.as_ref()),
|
||||
_ => expr,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user