Skip to content

Commit 067f9b5

Browse files
committedSep 10, 2024·
refactor(semantic): introduce IsGlobalReference trait (#5672)
1 parent 68c3cf5 commit 067f9b5

File tree

7 files changed

+61
-58
lines changed

7 files changed

+61
-58
lines changed
 

‎crates/oxc_linter/src/ast_util.rs

+2-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use oxc_ast::{ast::BindingIdentifier, AstKind};
2-
use oxc_semantic::{AstNode, AstNodeId, SymbolId};
2+
use oxc_semantic::{AstNode, AstNodeId, IsGlobalReference, SymbolId};
33
use oxc_span::{GetSpan, Span};
44
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator};
55

@@ -384,27 +384,11 @@ pub fn get_new_expr_ident_name<'a>(new_expr: &'a NewExpression<'a>) -> Option<&'
384384
Some(ident.name.as_str())
385385
}
386386

387-
/// Check if the given [IdentifierReference] is a global reference.
388-
/// Such as `window`, `document`, `globalThis`, etc.
389-
pub fn is_global_reference(ident: &IdentifierReference, ctx: &LintContext) -> bool {
390-
let symbol_table = ctx.semantic().symbols();
391-
let Some(reference_id) = ident.reference_id.get() else {
392-
return false;
393-
};
394-
let reference = symbol_table.get_reference(reference_id);
395-
reference.symbol_id().is_none()
396-
}
397-
398387
pub fn is_global_require_call(call_expr: &CallExpression, ctx: &LintContext) -> bool {
399388
if call_expr.arguments.len() != 1 {
400389
return false;
401390
}
402-
403-
if let Expression::Identifier(id_ref) = &call_expr.callee {
404-
id_ref.name == "require" && is_global_reference(id_ref, ctx)
405-
} else {
406-
false
407-
}
391+
call_expr.callee.is_global_reference_name("require", ctx.symbols())
408392
}
409393

410394
pub fn is_function_node(node: &AstNode) -> bool {

‎crates/oxc_linter/src/rules/eslint/no_new_func.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use oxc_ast::{ast::IdentifierReference, AstKind};
1+
use oxc_ast::AstKind;
22
use oxc_diagnostics::OxcDiagnostic;
33
use oxc_macros::declare_oxc_lint;
4+
use oxc_semantic::IsGlobalReference;
45
use oxc_span::Span;
56

67
use crate::{context::LintContext, rule::Rule, AstNode};
@@ -9,13 +10,6 @@ fn no_new_func(span: Span) -> OxcDiagnostic {
910
OxcDiagnostic::warn("The Function constructor is eval.").with_label(span)
1011
}
1112

12-
fn is_global_function_reference(ctx: &LintContext, id: &IdentifierReference) -> bool {
13-
if let Some(reference_id) = id.reference_id() {
14-
return id.name == "Function" && ctx.symbols().is_global_reference(reference_id);
15-
}
16-
false
17-
}
18-
1913
#[derive(Debug, Default, Clone)]
2014
pub struct NoNewFunc;
2115

@@ -99,7 +93,7 @@ impl Rule for NoNewFunc {
9993
};
10094

10195
if let Some((id, span)) = id_and_span {
102-
if is_global_function_reference(ctx, id) {
96+
if id.is_global_reference_name("Function", ctx.symbols()) {
10397
ctx.diagnostic(no_new_func(span));
10498
}
10599
}

‎crates/oxc_linter/src/rules/eslint/radix.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use oxc_ast::{
44
};
55
use oxc_diagnostics::OxcDiagnostic;
66
use oxc_macros::declare_oxc_lint;
7+
use oxc_semantic::IsGlobalReference;
78
use oxc_span::{GetSpan, Span};
89

910
use crate::{context::LintContext, rule::Rule, AstNode};
@@ -72,17 +73,14 @@ impl Rule for Radix {
7273

7374
match call_expr.callee.without_parentheses() {
7475
Expression::Identifier(ident) => {
75-
if ident.name == "parseInt"
76-
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
77-
{
76+
if ident.is_global_reference_name("parseInt", ctx.symbols()) {
7877
Self::check_arguments(self, call_expr, ctx);
7978
}
8079
}
8180
Expression::StaticMemberExpression(member_expr) => {
8281
if let Expression::Identifier(ident) = member_expr.object.without_parentheses() {
83-
if ident.name == "Number"
82+
if ident.is_global_reference_name("Number", ctx.symbols())
8483
&& member_expr.property.name == "parseInt"
85-
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
8684
{
8785
Self::check_arguments(self, call_expr, ctx);
8886
}
@@ -91,9 +89,8 @@ impl Rule for Radix {
9189
Expression::ChainExpression(chain_expr) => {
9290
if let Some(member_expr) = chain_expr.expression.as_member_expression() {
9391
if let Expression::Identifier(ident) = member_expr.object() {
94-
if ident.name == "Number"
92+
if ident.is_global_reference_name("Number", ctx.symbols())
9593
&& member_expr.static_property_name() == Some("parseInt")
96-
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
9794
{
9895
Self::check_arguments(self, call_expr, ctx);
9996
}

‎crates/oxc_linter/src/rules/node/no_exports_assign.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use oxc_ast::{
2-
ast::{AssignmentTarget, Expression, IdentifierReference, MemberExpression},
2+
ast::{AssignmentTarget, Expression, MemberExpression},
33
AstKind,
44
};
55
use oxc_diagnostics::OxcDiagnostic;
66
use oxc_macros::declare_oxc_lint;
7+
use oxc_semantic::IsGlobalReference;
78
use oxc_span::{GetSpan, Span};
89

910
use crate::{context::LintContext, rule::Rule, AstNode};
@@ -14,19 +15,11 @@ fn no_exports_assign(span: Span) -> OxcDiagnostic {
1415
.with_help("Unexpected assignment to 'exports' variable. Use 'module.exports' instead.")
1516
}
1617

17-
fn is_global_reference(ctx: &LintContext, id: &IdentifierReference, name: &str) -> bool {
18-
if let Some(reference_id) = id.reference_id() {
19-
return id.name == name && ctx.symbols().is_global_reference(reference_id);
20-
}
21-
false
22-
}
23-
2418
fn is_exports(node: &AssignmentTarget, ctx: &LintContext) -> bool {
2519
let AssignmentTarget::AssignmentTargetIdentifier(id) = node else {
2620
return false;
2721
};
28-
29-
is_global_reference(ctx, id, "exports")
22+
id.is_global_reference_name("exports", ctx.symbols())
3023
}
3124

3225
fn is_module_exports(expr: Option<&MemberExpression>, ctx: &LintContext) -> bool {
@@ -39,7 +32,7 @@ fn is_module_exports(expr: Option<&MemberExpression>, ctx: &LintContext) -> bool
3932
};
4033

4134
return mem_expr.static_property_name() == Some("exports")
42-
&& is_global_reference(ctx, obj_id, "module");
35+
&& obj_id.is_global_reference_name("module", ctx.symbols());
4336
}
4437

4538
#[derive(Debug, Default, Clone)]

‎crates/oxc_minifier/src/node_util/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::borrow::Cow;
88
use num_bigint::BigInt;
99
use num_traits::{One, Zero};
1010
use oxc_ast::ast::*;
11-
use oxc_semantic::{ScopeTree, SymbolTable};
11+
use oxc_semantic::{IsGlobalReference, ScopeTree, SymbolTable};
1212
use oxc_syntax::operator::{AssignmentOperator, LogicalOperator, UnaryOperator};
1313

1414
pub use self::{
@@ -34,7 +34,7 @@ pub trait NodeUtil {
3434
}
3535

3636
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {
37-
if ident.name == "undefined" && self.symbols().is_global_identifier_reference(ident) {
37+
if ident.name == "undefined" && ident.is_global_reference(self.symbols()) {
3838
return true;
3939
}
4040
false

‎crates/oxc_semantic/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub use oxc_syntax::{
4040
pub use crate::{
4141
reference::{Reference, ReferenceFlags, ReferenceId},
4242
scope::ScopeTree,
43-
symbol::SymbolTable,
43+
symbol::{IsGlobalReference, SymbolTable},
4444
};
4545

4646
/// Semantic analysis of a JavaScript/TypeScript program.

‎crates/oxc_semantic/src/symbol.rs

+45-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(non_snake_case)] // Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
22

3-
use oxc_ast::ast::IdentifierReference;
3+
use oxc_ast::ast::{Expression, IdentifierReference};
44
use oxc_index::IndexVec;
55
use oxc_span::{CompactStr, Span};
66
pub use oxc_syntax::{
@@ -172,15 +172,6 @@ impl SymbolTable {
172172
self.references[reference_id].symbol_id().is_some()
173173
}
174174

175-
#[inline]
176-
pub fn is_global_reference(&self, reference_id: ReferenceId) -> bool {
177-
self.references[reference_id].symbol_id().is_none()
178-
}
179-
180-
pub fn is_global_identifier_reference(&self, ident: &IdentifierReference<'_>) -> bool {
181-
ident.reference_id.get().is_some_and(|reference_id| self.is_global_reference(reference_id))
182-
}
183-
184175
#[inline]
185176
pub fn get_resolved_reference_ids(&self, symbol_id: SymbolId) -> &Vec<ReferenceId> {
186177
&self.resolved_references[symbol_id]
@@ -217,3 +208,47 @@ impl SymbolTable {
217208
self.references.reserve(additional_references);
218209
}
219210
}
211+
212+
/// Checks whether the a identifier reference is a global value or not.
213+
pub trait IsGlobalReference {
214+
fn is_global_reference(&self, _symbols: &SymbolTable) -> bool;
215+
fn is_global_reference_name(&self, name: &str, _symbols: &SymbolTable) -> bool;
216+
}
217+
218+
impl IsGlobalReference for ReferenceId {
219+
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
220+
symbols.references[*self].symbol_id().is_none()
221+
}
222+
223+
fn is_global_reference_name(&self, _name: &str, _symbols: &SymbolTable) -> bool {
224+
panic!("This function is pointless to be called.");
225+
}
226+
}
227+
228+
impl<'a> IsGlobalReference for IdentifierReference<'a> {
229+
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
230+
self.reference_id
231+
.get()
232+
.is_some_and(|reference_id| reference_id.is_global_reference(symbols))
233+
}
234+
235+
fn is_global_reference_name(&self, name: &str, symbols: &SymbolTable) -> bool {
236+
self.name == name && self.is_global_reference(symbols)
237+
}
238+
}
239+
240+
impl<'a> IsGlobalReference for Expression<'a> {
241+
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
242+
if let Expression::Identifier(ident) = self {
243+
return ident.is_global_reference(symbols);
244+
}
245+
false
246+
}
247+
248+
fn is_global_reference_name(&self, name: &str, symbols: &SymbolTable) -> bool {
249+
if let Expression::Identifier(ident) = self {
250+
return ident.is_global_reference_name(name, symbols);
251+
}
252+
false
253+
}
254+
}

0 commit comments

Comments
 (0)
Please sign in to comment.