mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(linter/no-unused-vars): false positives in TS type assertions (#6397)
Fixes several false positive cases for referenced variables and declarations
that are inside type casts, `as` expressions, `satisfies` expressions, non-null
assertions, and the like.
```js
function foo(el) { return el + 1 }
const arr = [1, 2, 3]
const mapped = arr.map(foo as unknown as SomePredicateType)
```
This commit is contained in:
parent
d3e59c6a6d
commit
ba53bc9942
4 changed files with 21 additions and 7 deletions
|
|
@ -24,7 +24,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
assert!(kind.is_function_like() || matches!(kind, AstKind::Class(_)));
|
||||
}
|
||||
|
||||
for parent in self.iter_parents() {
|
||||
for parent in self.iter_relevant_parents() {
|
||||
match parent.kind() {
|
||||
AstKind::MemberExpression(_) | AstKind::ParenthesizedExpression(_)
|
||||
// e.g. `const x = [function foo() {}]`
|
||||
|
|
|
|||
|
|
@ -105,7 +105,12 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
self.nodes().iter_parents(self.declaration_id())
|
||||
}
|
||||
|
||||
pub fn iter_relevant_parents(
|
||||
#[inline]
|
||||
pub fn iter_relevant_parents(&self) -> impl Iterator<Item = &AstNode<'a>> + Clone + '_ {
|
||||
self.iter_relevant_parents_of(self.declaration_id())
|
||||
}
|
||||
|
||||
pub fn iter_relevant_parents_of(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
) -> impl Iterator<Item = &AstNode<'a>> + Clone + '_ {
|
||||
|
|
@ -131,7 +136,15 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
|
||||
#[inline]
|
||||
const fn is_relevant_kind(kind: AstKind<'a>) -> bool {
|
||||
!matches!(kind, AstKind::ParenthesizedExpression(_))
|
||||
!matches!(
|
||||
kind,
|
||||
AstKind::ParenthesizedExpression(_)
|
||||
| AstKind::TSAsExpression(_)
|
||||
| AstKind::TSSatisfiesExpression(_)
|
||||
| AstKind::TSInstantiationExpression(_)
|
||||
| AstKind::TSNonNullExpression(_)
|
||||
| AstKind::TSTypeAssertion(_)
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://github.com/oxc-project/oxc/issues/4739>
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ fn test_used_declarations() {
|
|||
// first put into an intermediate (e.g. an object or array)
|
||||
"arr.reduce(function reducer (acc, el) { return acc + el }, 0)",
|
||||
"console.log({ foo: function foo() {} })",
|
||||
"console.log({ foo: function foo() {} as unknown as Function })",
|
||||
"test.each([ function foo() {} ])('test some function', (fn) => { expect(fn(1)).toBe(1) })",
|
||||
"export default { foo() {} }",
|
||||
"const arr = [function foo() {}, function bar() {}]; console.log(arr[0]())",
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
/// type Foo = Array<Bar>
|
||||
/// ```
|
||||
fn is_type_self_usage(&self, reference: &Reference) -> bool {
|
||||
for parent in self.iter_relevant_parents(reference.node_id()).map(AstNode::kind) {
|
||||
for parent in self.iter_relevant_parents_of(reference.node_id()).map(AstNode::kind) {
|
||||
match parent {
|
||||
AstKind::TSTypeAliasDeclaration(decl) => {
|
||||
return self == &decl.id;
|
||||
|
|
@ -425,7 +425,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
|
||||
/// Check if a [`AstNode`] is within a return statement or implicit return.
|
||||
fn is_in_return_statement(&self, node_id: NodeId) -> bool {
|
||||
for parent in self.iter_relevant_parents(node_id).map(AstNode::kind) {
|
||||
for parent in self.iter_relevant_parents_of(node_id).map(AstNode::kind) {
|
||||
match parent {
|
||||
AstKind::ReturnStatement(_) => return true,
|
||||
AstKind::ExpressionStatement(_) => continue,
|
||||
|
|
@ -652,7 +652,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
/// 2. "relevant" nodes are non "transparent". For example, parenthesis are "transparent".
|
||||
#[inline]
|
||||
fn get_ref_relevant_node(&self, reference: &Reference) -> Option<&AstNode<'a>> {
|
||||
self.iter_relevant_parents(reference.node_id()).next()
|
||||
self.iter_relevant_parents_of(reference.node_id()).next()
|
||||
}
|
||||
|
||||
/// Find the [`SymbolId`] for the nearest function declaration or expression
|
||||
|
|
@ -662,7 +662,7 @@ impl<'s, 'a> Symbol<'s, 'a> {
|
|||
// name from the variable its assigned to.
|
||||
let mut needs_variable_identifier = false;
|
||||
|
||||
for parent in self.iter_relevant_parents(node_id) {
|
||||
for parent in self.iter_relevant_parents_of(node_id) {
|
||||
match parent.kind() {
|
||||
AstKind::Function(f) => {
|
||||
return f.id.as_ref().and_then(|id| id.symbol_id.get());
|
||||
|
|
|
|||
Loading…
Reference in a new issue