mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): improve no_redeclare rule implementation (#2084)
This commit is contained in:
parent
a9e2158362
commit
721a869b6e
4 changed files with 51 additions and 17 deletions
|
|
@ -58,7 +58,7 @@ declare_oxc_lint!(
|
||||||
/// var a = 10;
|
/// var a = 10;
|
||||||
/// ```
|
/// ```
|
||||||
NoRedeclare,
|
NoRedeclare,
|
||||||
nursery // There are false positives within TypeScript files (e.g. redeclare on interface)
|
pedantic
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Rule for NoRedeclare {
|
impl Rule for NoRedeclare {
|
||||||
|
|
@ -81,16 +81,20 @@ impl Rule for NoRedeclare {
|
||||||
match ctx.nodes().kind(decl) {
|
match ctx.nodes().kind(decl) {
|
||||||
AstKind::VariableDeclarator(var) => {
|
AstKind::VariableDeclarator(var) => {
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = &var.id.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = &var.id.kind {
|
||||||
|
if *symbol_table.get_name(variable.symbol_id) == ident.name {
|
||||||
self.report_diagnostic(ctx, variable, ident);
|
self.report_diagnostic(ctx, variable, ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
AstKind::FormalParameters(params) => {
|
AstKind::FormalParameters(params) => {
|
||||||
for item in ¶ms.items {
|
for item in ¶ms.items {
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = &item.pattern.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = &item.pattern.kind {
|
||||||
|
if *symbol_table.get_name(variable.symbol_id) == ident.name {
|
||||||
self.report_diagnostic(ctx, variable, ident);
|
self.report_diagnostic(ctx, variable, ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +110,7 @@ impl NoRedeclare {
|
||||||
) {
|
) {
|
||||||
if self.built_in_globals && BUILTINS.get(&ident.name).is_some() {
|
if self.built_in_globals && BUILTINS.get(&ident.name).is_some() {
|
||||||
ctx.diagnostic(NoRedeclareAsBuiltiInDiagnostic(ident.name.clone(), ident.span));
|
ctx.diagnostic(NoRedeclareAsBuiltiInDiagnostic(ident.name.clone(), ident.span));
|
||||||
} else if variable.name == ident.name && variable.span != ident.span {
|
} else if variable.span != ident.span {
|
||||||
ctx.diagnostic(NoRedeclareDiagnostic(ident.name.clone(), ident.span, variable.span));
|
ctx.diagnostic(NoRedeclareDiagnostic(ident.name.clone(), ident.span, variable.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,12 +157,10 @@ fn test() {
|
||||||
("var a = 3; var a = 10; var a = 15;", None),
|
("var a = 3; var a = 10; var a = 15;", None),
|
||||||
("var a; var a;", None),
|
("var a; var a;", None),
|
||||||
("export var a; var a;", None),
|
("export var a; var a;", None),
|
||||||
// `var` redeclaration in class static blocks. Redeclaration of functions is not allowed in class static blocks.
|
|
||||||
("class C { static { var a; var a; } }", None),
|
("class C { static { var a; var a; } }", None),
|
||||||
// Todo: Fix me
|
("class C { static { var a; { var a; } } }", None),
|
||||||
// ("class C { static { var a; { var a; } } }", None),
|
("class C { static { { var a; } var a; } }", None),
|
||||||
// ("class C { static { { var a; } var a; } }", None),
|
("class C { static { { var a; } { var a; } } }", None),
|
||||||
// ("class C { static { { var a; } { var a; } } }", None),
|
|
||||||
// ("var Object = 0;", Some(serde_json::json!([{ "builtinGlobals": true }]))),
|
// ("var Object = 0;", Some(serde_json::json!([{ "builtinGlobals": true }]))),
|
||||||
(
|
(
|
||||||
"var a; var {a = 0, b: Object = 0} = {};",
|
"var a; var {a = 0, b: Object = 0} = {};",
|
||||||
|
|
@ -171,7 +173,7 @@ fn test() {
|
||||||
),
|
),
|
||||||
("function f() { var a; var a; }", None),
|
("function f() { var a; var a; }", None),
|
||||||
("function f(a) { var a; }", None),
|
("function f(a) { var a; }", None),
|
||||||
// ("function f() { var a; if (test) { var a; } }", None),
|
("function f() { var a; if (test) { var a; } }", None),
|
||||||
("for (var a, a;;);", None),
|
("for (var a, a;;);", None),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,30 @@ expression: no_redeclare
|
||||||
· ╰── 'a' is already defined.
|
· ╰── 'a' is already defined.
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
|
╭─[no_redeclare.tsx:1:1]
|
||||||
|
1 │ class C { static { var a; { var a; } } }
|
||||||
|
· ┬ ┬
|
||||||
|
· │ ╰── It can not be redeclare here.
|
||||||
|
· ╰── 'a' is already defined.
|
||||||
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
|
╭─[no_redeclare.tsx:1:1]
|
||||||
|
1 │ class C { static { { var a; } var a; } }
|
||||||
|
· ┬ ┬
|
||||||
|
· │ ╰── It can not be redeclare here.
|
||||||
|
· ╰── 'a' is already defined.
|
||||||
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
|
╭─[no_redeclare.tsx:1:1]
|
||||||
|
1 │ class C { static { { var a; } { var a; } } }
|
||||||
|
· ┬ ┬
|
||||||
|
· │ ╰── It can not be redeclare here.
|
||||||
|
· ╰── 'a' is already defined.
|
||||||
|
╰────
|
||||||
|
|
||||||
⚠ eslint(no-redeclare): 'a' is already defined.
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
╭─[no_redeclare.tsx:1:1]
|
╭─[no_redeclare.tsx:1:1]
|
||||||
1 │ var a; var {a = 0, b: Object = 0} = {};
|
1 │ var a; var {a = 0, b: Object = 0} = {};
|
||||||
|
|
@ -132,6 +156,14 @@ expression: no_redeclare
|
||||||
· ╰── 'a' is already defined.
|
· ╰── 'a' is already defined.
|
||||||
╰────
|
╰────
|
||||||
|
|
||||||
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
|
╭─[no_redeclare.tsx:1:1]
|
||||||
|
1 │ function f() { var a; if (test) { var a; } }
|
||||||
|
· ┬ ┬
|
||||||
|
· │ ╰── It can not be redeclare here.
|
||||||
|
· ╰── 'a' is already defined.
|
||||||
|
╰────
|
||||||
|
|
||||||
⚠ eslint(no-redeclare): 'a' is already defined.
|
⚠ eslint(no-redeclare): 'a' is already defined.
|
||||||
╭─[no_redeclare.tsx:1:1]
|
╭─[no_redeclare.tsx:1:1]
|
||||||
1 │ for (var a, a;;);
|
1 │ for (var a, a;;);
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,10 @@ impl<'a> Binder for VariableDeclarator<'a> {
|
||||||
builder.check_redeclaration(*scope_id, span, name, excludes, true)
|
builder.check_redeclaration(*scope_id, span, name, excludes, true)
|
||||||
{
|
{
|
||||||
ident.symbol_id.set(Some(symbol_id));
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
builder.add_redeclared_variables(VariableInfo {
|
if self.kind.is_var() {
|
||||||
name: ident.name.clone(),
|
builder
|
||||||
span: ident.span,
|
.add_redeclared_variables(VariableInfo { span: ident.span, symbol_id });
|
||||||
symbol_id,
|
}
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ struct UnusedLabels<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VariableInfo {
|
pub struct VariableInfo {
|
||||||
pub name: Atom,
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub symbol_id: SymbolId,
|
pub symbol_id: SymbolId,
|
||||||
}
|
}
|
||||||
|
|
@ -253,7 +252,9 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
) -> SymbolId {
|
) -> SymbolId {
|
||||||
if let Some(symbol_id) = self.check_redeclaration(scope_id, span, name, excludes, true) {
|
if let Some(symbol_id) = self.check_redeclaration(scope_id, span, name, excludes, true) {
|
||||||
self.symbols.union_flag(symbol_id, includes);
|
self.symbols.union_flag(symbol_id, includes);
|
||||||
self.add_redeclared_variables(VariableInfo { name: name.clone(), span, symbol_id });
|
if includes.is_function_scoped_declaration() {
|
||||||
|
self.add_redeclared_variables(VariableInfo { span, symbol_id });
|
||||||
|
}
|
||||||
return symbol_id;
|
return symbol_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue