Skip to content

Commit

Permalink
feat(semantic,syntax): add SymbolFlags::ArrowFunction (#4946)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DonIsaac committed Aug 18, 2024
1 parent 915cb4d commit 48821c0
Show file tree
Hide file tree
Showing 27 changed files with 65 additions and 39 deletions.
8 changes: 7 additions & 1 deletion crates/oxc_semantic/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
46 changes: 33 additions & 13 deletions crates/oxc_syntax/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 48821c0

Please sign in to comment.