mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(semantic,syntax): add SymbolFlags::ArrowFunction (#4946)
There are many cases in lint rules where we want to see if a symbol is a function by checking its SymbolFlags. This is currently not fully possible, since variables assigned to arrow functions are not distinguished from any other kind of variable. This PR adds `SymbolFlags::ArrowFunction` for variables that are initialized to arrow functions. Symbols that are re-assigned to arrow functions will not have this flag, but this is acceptable for lint rules.
This commit is contained in:
parent
915cb4d5a3
commit
48821c0110
27 changed files with 65 additions and 39 deletions
|
|
@ -19,7 +19,7 @@ pub(crate) trait Binder<'a> {
|
||||||
|
|
||||||
impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
||||||
fn bind(&self, builder: &mut SemanticBuilder<'a>) {
|
fn bind(&self, builder: &mut SemanticBuilder<'a>) {
|
||||||
let (includes, excludes) = match self.kind {
|
let (mut includes, excludes) = match self.kind {
|
||||||
VariableDeclarationKind::Const => (
|
VariableDeclarationKind::Const => (
|
||||||
SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable,
|
SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable,
|
||||||
SymbolFlags::BlockScopedVariableExcludes,
|
SymbolFlags::BlockScopedVariableExcludes,
|
||||||
|
|
@ -32,6 +32,12 @@ impl<'a> Binder<'a> for VariableDeclarator<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if self.init.as_ref().is_some_and(|init| {
|
||||||
|
matches!(init.get_inner_expression(), Expression::ArrowFunctionExpression(_))
|
||||||
|
}) {
|
||||||
|
includes |= SymbolFlags::ArrowFunction;
|
||||||
|
}
|
||||||
|
|
||||||
if self.kind.is_lexical() {
|
if self.kind.is_lexical() {
|
||||||
self.id.bound_names(&mut |ident| {
|
self.id.bound_names(&mut |ident| {
|
||||||
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
|
let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/call-expression
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"references": []
|
"references": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "arrow",
|
"name": "arrow",
|
||||||
"node": "VariableDeclarator(arrow)",
|
"node": "VariableDeclarator(arrow)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"node": "VariableDeclarator(foo)",
|
"node": "VariableDeclarator(foo)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(FunctionScopedVariable)",
|
"flag": "SymbolFlags(FunctionScopedVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
||||||
"node": "Program",
|
"node": "Program",
|
||||||
"symbols": [
|
"symbols": [
|
||||||
{
|
{
|
||||||
"flag": "SymbolFlags(FunctionScopedVariable)",
|
"flag": "SymbolFlags(FunctionScopedVariable | ArrowFunction)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "top",
|
"name": "top",
|
||||||
"node": "VariableDeclarator(top)",
|
"node": "VariableDeclarator(top)",
|
||||||
|
|
|
||||||
|
|
@ -77,22 +77,28 @@ bitflags! {
|
||||||
/// Is this symbol inside an export declaration
|
/// Is this symbol inside an export declaration
|
||||||
const Export = 1 << 4;
|
const Export = 1 << 4;
|
||||||
const Class = 1 << 5;
|
const Class = 1 << 5;
|
||||||
const CatchVariable = 1 << 6; // try {} catch(catch_variable) {}
|
/// `try {} catch(catch_variable) {}`
|
||||||
|
const CatchVariable = 1 << 6;
|
||||||
|
/// A function declaration or expression
|
||||||
const Function = 1 << 7;
|
const Function = 1 << 7;
|
||||||
const Import = 1 << 8; // Imported ESM binding
|
/// A function or block-scoped variable initialized to an arrow function
|
||||||
const TypeImport = 1 << 9; // Imported ESM type-only binding
|
const ArrowFunction = 1 << 8;
|
||||||
|
/// Imported ESM binding
|
||||||
|
const Import = 1 << 9;
|
||||||
|
/// Imported ESM type-only binding
|
||||||
|
const TypeImport = 1 << 10;
|
||||||
// Type specific symbol flags
|
// Type specific symbol flags
|
||||||
const TypeAlias = 1 << 10;
|
const TypeAlias = 1 << 11;
|
||||||
const Interface = 1 << 11;
|
const Interface = 1 << 12;
|
||||||
const RegularEnum = 1 << 12;
|
const RegularEnum = 1 << 13;
|
||||||
const ConstEnum = 1 << 13;
|
const ConstEnum = 1 << 14;
|
||||||
const EnumMember = 1 << 14;
|
const EnumMember = 1 << 15;
|
||||||
const TypeLiteral = 1 << 15;
|
const TypeLiteral = 1 << 16;
|
||||||
const TypeParameter = 1 << 16;
|
const TypeParameter = 1 << 17;
|
||||||
const NameSpaceModule = 1 << 17;
|
const NameSpaceModule = 1 << 18;
|
||||||
const ValueModule = 1 << 18;
|
const ValueModule = 1 << 19;
|
||||||
// In a dts file or there is a declare flag
|
// In a dts file or there is a declare flag
|
||||||
const Ambient = 1 << 19;
|
const Ambient = 1 << 20;
|
||||||
|
|
||||||
const Enum = Self::ConstEnum.bits() | Self::RegularEnum.bits();
|
const Enum = Self::ConstEnum.bits() | Self::RegularEnum.bits();
|
||||||
|
|
||||||
|
|
@ -150,11 +156,25 @@ impl SymbolFlags {
|
||||||
self.contains(Self::ConstVariable)
|
self.contains(Self::ConstVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this symbol is a function declaration or expression.
|
||||||
|
///
|
||||||
|
/// Use [`SymbolFlags::is_function_like`] to check if this symbol is a function or an arrow function.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_function(&self) -> bool {
|
pub fn is_function(&self) -> bool {
|
||||||
self.contains(Self::Function)
|
self.contains(Self::Function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_arrow_function(&self) -> bool {
|
||||||
|
self.contains(Self::ArrowFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this symbol is an arrow function or a function declaration/expression.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_function_like(&self) -> bool {
|
||||||
|
self.intersects(Self::Function | Self::ArrowFunction)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_class(&self) -> bool {
|
pub fn is_class(&self) -> bool {
|
||||||
self.contains(Self::Class)
|
self.contains(Self::Class)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue