mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +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> {
|
||||
fn bind(&self, builder: &mut SemanticBuilder<'a>) {
|
||||
let (includes, excludes) = match self.kind {
|
||||
let (mut includes, excludes) = match self.kind {
|
||||
VariableDeclarationKind::Const => (
|
||||
SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable,
|
||||
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() {
|
||||
self.id.bound_names(&mut |ident| {
|
||||
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",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "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,
|
||||
"name": "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,
|
||||
"name": "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,
|
||||
"name": "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,
|
||||
"name": "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,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"references": []
|
||||
},
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||
"id": 1,
|
||||
"name": "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,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "arrow",
|
||||
"node": "VariableDeclarator(arrow)",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "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,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/functions/arrow
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "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,
|
||||
"name": "foo",
|
||||
"node": "VariableDeclarator(foo)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(FunctionScopedVariable)",
|
||||
"flag": "SymbolFlags(FunctionScopedVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ConstVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(BlockScopedVariable)",
|
||||
"flag": "SymbolFlags(BlockScopedVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/global-resoluti
|
|||
"node": "Program",
|
||||
"symbols": [
|
||||
{
|
||||
"flag": "SymbolFlags(FunctionScopedVariable)",
|
||||
"flag": "SymbolFlags(FunctionScopedVariable | ArrowFunction)",
|
||||
"id": 0,
|
||||
"name": "top",
|
||||
"node": "VariableDeclarator(top)",
|
||||
|
|
|
|||
|
|
@ -77,22 +77,28 @@ bitflags! {
|
|||
/// Is this symbol inside an export declaration
|
||||
const Export = 1 << 4;
|
||||
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 Import = 1 << 8; // Imported ESM binding
|
||||
const TypeImport = 1 << 9; // Imported ESM type-only binding
|
||||
/// A function or block-scoped variable initialized to an arrow function
|
||||
const ArrowFunction = 1 << 8;
|
||||
/// Imported ESM binding
|
||||
const Import = 1 << 9;
|
||||
/// Imported ESM type-only binding
|
||||
const TypeImport = 1 << 10;
|
||||
// Type specific symbol flags
|
||||
const TypeAlias = 1 << 10;
|
||||
const Interface = 1 << 11;
|
||||
const RegularEnum = 1 << 12;
|
||||
const ConstEnum = 1 << 13;
|
||||
const EnumMember = 1 << 14;
|
||||
const TypeLiteral = 1 << 15;
|
||||
const TypeParameter = 1 << 16;
|
||||
const NameSpaceModule = 1 << 17;
|
||||
const ValueModule = 1 << 18;
|
||||
const TypeAlias = 1 << 11;
|
||||
const Interface = 1 << 12;
|
||||
const RegularEnum = 1 << 13;
|
||||
const ConstEnum = 1 << 14;
|
||||
const EnumMember = 1 << 15;
|
||||
const TypeLiteral = 1 << 16;
|
||||
const TypeParameter = 1 << 17;
|
||||
const NameSpaceModule = 1 << 18;
|
||||
const ValueModule = 1 << 19;
|
||||
// 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();
|
||||
|
||||
|
|
@ -150,11 +156,25 @@ impl SymbolFlags {
|
|||
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]
|
||||
pub fn is_function(&self) -> bool {
|
||||
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]
|
||||
pub fn is_class(&self) -> bool {
|
||||
self.contains(Self::Class)
|
||||
|
|
|
|||
Loading…
Reference in a new issue