mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(semantic): introduce IsGlobalReference trait (#5672)
This commit is contained in:
parent
68c3cf544f
commit
067f9b5a6f
7 changed files with 61 additions and 58 deletions
|
|
@ -1,5 +1,5 @@
|
|||
use oxc_ast::{ast::BindingIdentifier, AstKind};
|
||||
use oxc_semantic::{AstNode, AstNodeId, SymbolId};
|
||||
use oxc_semantic::{AstNode, AstNodeId, IsGlobalReference, SymbolId};
|
||||
use oxc_span::{GetSpan, Span};
|
||||
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator};
|
||||
|
||||
|
|
@ -384,27 +384,11 @@ pub fn get_new_expr_ident_name<'a>(new_expr: &'a NewExpression<'a>) -> Option<&'
|
|||
Some(ident.name.as_str())
|
||||
}
|
||||
|
||||
/// Check if the given [IdentifierReference] is a global reference.
|
||||
/// Such as `window`, `document`, `globalThis`, etc.
|
||||
pub fn is_global_reference(ident: &IdentifierReference, ctx: &LintContext) -> bool {
|
||||
let symbol_table = ctx.semantic().symbols();
|
||||
let Some(reference_id) = ident.reference_id.get() else {
|
||||
return false;
|
||||
};
|
||||
let reference = symbol_table.get_reference(reference_id);
|
||||
reference.symbol_id().is_none()
|
||||
}
|
||||
|
||||
pub fn is_global_require_call(call_expr: &CallExpression, ctx: &LintContext) -> bool {
|
||||
if call_expr.arguments.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Expression::Identifier(id_ref) = &call_expr.callee {
|
||||
id_ref.name == "require" && is_global_reference(id_ref, ctx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
call_expr.callee.is_global_reference_name("require", ctx.symbols())
|
||||
}
|
||||
|
||||
pub fn is_function_node(node: &AstNode) -> bool {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use oxc_ast::{ast::IdentifierReference, AstKind};
|
||||
use oxc_ast::AstKind;
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_semantic::IsGlobalReference;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
|
@ -9,13 +10,6 @@ fn no_new_func(span: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::warn("The Function constructor is eval.").with_label(span)
|
||||
}
|
||||
|
||||
fn is_global_function_reference(ctx: &LintContext, id: &IdentifierReference) -> bool {
|
||||
if let Some(reference_id) = id.reference_id() {
|
||||
return id.name == "Function" && ctx.symbols().is_global_reference(reference_id);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoNewFunc;
|
||||
|
||||
|
|
@ -99,7 +93,7 @@ impl Rule for NoNewFunc {
|
|||
};
|
||||
|
||||
if let Some((id, span)) = id_and_span {
|
||||
if is_global_function_reference(ctx, id) {
|
||||
if id.is_global_reference_name("Function", ctx.symbols()) {
|
||||
ctx.diagnostic(no_new_func(span));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use oxc_ast::{
|
|||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_semantic::IsGlobalReference;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
|
@ -72,17 +73,14 @@ impl Rule for Radix {
|
|||
|
||||
match call_expr.callee.without_parentheses() {
|
||||
Expression::Identifier(ident) => {
|
||||
if ident.name == "parseInt"
|
||||
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
|
||||
{
|
||||
if ident.is_global_reference_name("parseInt", ctx.symbols()) {
|
||||
Self::check_arguments(self, call_expr, ctx);
|
||||
}
|
||||
}
|
||||
Expression::StaticMemberExpression(member_expr) => {
|
||||
if let Expression::Identifier(ident) = member_expr.object.without_parentheses() {
|
||||
if ident.name == "Number"
|
||||
if ident.is_global_reference_name("Number", ctx.symbols())
|
||||
&& member_expr.property.name == "parseInt"
|
||||
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
|
||||
{
|
||||
Self::check_arguments(self, call_expr, ctx);
|
||||
}
|
||||
|
|
@ -91,9 +89,8 @@ impl Rule for Radix {
|
|||
Expression::ChainExpression(chain_expr) => {
|
||||
if let Some(member_expr) = chain_expr.expression.as_member_expression() {
|
||||
if let Expression::Identifier(ident) = member_expr.object() {
|
||||
if ident.name == "Number"
|
||||
if ident.is_global_reference_name("Number", ctx.symbols())
|
||||
&& member_expr.static_property_name() == Some("parseInt")
|
||||
&& ctx.symbols().is_global_reference(ident.reference_id().unwrap())
|
||||
{
|
||||
Self::check_arguments(self, call_expr, ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use oxc_ast::{
|
||||
ast::{AssignmentTarget, Expression, IdentifierReference, MemberExpression},
|
||||
ast::{AssignmentTarget, Expression, MemberExpression},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_semantic::IsGlobalReference;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
|
@ -14,19 +15,11 @@ fn no_exports_assign(span: Span) -> OxcDiagnostic {
|
|||
.with_help("Unexpected assignment to 'exports' variable. Use 'module.exports' instead.")
|
||||
}
|
||||
|
||||
fn is_global_reference(ctx: &LintContext, id: &IdentifierReference, name: &str) -> bool {
|
||||
if let Some(reference_id) = id.reference_id() {
|
||||
return id.name == name && ctx.symbols().is_global_reference(reference_id);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_exports(node: &AssignmentTarget, ctx: &LintContext) -> bool {
|
||||
let AssignmentTarget::AssignmentTargetIdentifier(id) = node else {
|
||||
return false;
|
||||
};
|
||||
|
||||
is_global_reference(ctx, id, "exports")
|
||||
id.is_global_reference_name("exports", ctx.symbols())
|
||||
}
|
||||
|
||||
fn is_module_exports(expr: Option<&MemberExpression>, ctx: &LintContext) -> bool {
|
||||
|
|
@ -39,7 +32,7 @@ fn is_module_exports(expr: Option<&MemberExpression>, ctx: &LintContext) -> bool
|
|||
};
|
||||
|
||||
return mem_expr.static_property_name() == Some("exports")
|
||||
&& is_global_reference(ctx, obj_id, "module");
|
||||
&& obj_id.is_global_reference_name("module", ctx.symbols());
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::borrow::Cow;
|
|||
use num_bigint::BigInt;
|
||||
use num_traits::{One, Zero};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_semantic::{ScopeTree, SymbolTable};
|
||||
use oxc_semantic::{IsGlobalReference, ScopeTree, SymbolTable};
|
||||
use oxc_syntax::operator::{AssignmentOperator, LogicalOperator, UnaryOperator};
|
||||
|
||||
pub use self::{
|
||||
|
|
@ -34,7 +34,7 @@ pub trait NodeUtil {
|
|||
}
|
||||
|
||||
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {
|
||||
if ident.name == "undefined" && self.symbols().is_global_identifier_reference(ident) {
|
||||
if ident.name == "undefined" && ident.is_global_reference(self.symbols()) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ pub use oxc_syntax::{
|
|||
pub use crate::{
|
||||
reference::{Reference, ReferenceFlags, ReferenceId},
|
||||
scope::ScopeTree,
|
||||
symbol::SymbolTable,
|
||||
symbol::{IsGlobalReference, SymbolTable},
|
||||
};
|
||||
|
||||
/// Semantic analysis of a JavaScript/TypeScript program.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(non_snake_case)] // Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
|
||||
use oxc_ast::ast::IdentifierReference;
|
||||
use oxc_ast::ast::{Expression, IdentifierReference};
|
||||
use oxc_index::IndexVec;
|
||||
use oxc_span::{CompactStr, Span};
|
||||
pub use oxc_syntax::{
|
||||
|
|
@ -172,15 +172,6 @@ impl SymbolTable {
|
|||
self.references[reference_id].symbol_id().is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_global_reference(&self, reference_id: ReferenceId) -> bool {
|
||||
self.references[reference_id].symbol_id().is_none()
|
||||
}
|
||||
|
||||
pub fn is_global_identifier_reference(&self, ident: &IdentifierReference<'_>) -> bool {
|
||||
ident.reference_id.get().is_some_and(|reference_id| self.is_global_reference(reference_id))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_resolved_reference_ids(&self, symbol_id: SymbolId) -> &Vec<ReferenceId> {
|
||||
&self.resolved_references[symbol_id]
|
||||
|
|
@ -217,3 +208,47 @@ impl SymbolTable {
|
|||
self.references.reserve(additional_references);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the a identifier reference is a global value or not.
|
||||
pub trait IsGlobalReference {
|
||||
fn is_global_reference(&self, _symbols: &SymbolTable) -> bool;
|
||||
fn is_global_reference_name(&self, name: &str, _symbols: &SymbolTable) -> bool;
|
||||
}
|
||||
|
||||
impl IsGlobalReference for ReferenceId {
|
||||
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
|
||||
symbols.references[*self].symbol_id().is_none()
|
||||
}
|
||||
|
||||
fn is_global_reference_name(&self, _name: &str, _symbols: &SymbolTable) -> bool {
|
||||
panic!("This function is pointless to be called.");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IsGlobalReference for IdentifierReference<'a> {
|
||||
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
|
||||
self.reference_id
|
||||
.get()
|
||||
.is_some_and(|reference_id| reference_id.is_global_reference(symbols))
|
||||
}
|
||||
|
||||
fn is_global_reference_name(&self, name: &str, symbols: &SymbolTable) -> bool {
|
||||
self.name == name && self.is_global_reference(symbols)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IsGlobalReference for Expression<'a> {
|
||||
fn is_global_reference(&self, symbols: &SymbolTable) -> bool {
|
||||
if let Expression::Identifier(ident) = self {
|
||||
return ident.is_global_reference(symbols);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_global_reference_name(&self, name: &str, symbols: &SymbolTable) -> bool {
|
||||
if let Expression::Identifier(ident) = self {
|
||||
return ident.is_global_reference_name(name, symbols);
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue