refactor(semantic): introduce IsGlobalReference trait (#5672)

This commit is contained in:
Boshen 2024-09-10 10:12:08 +00:00
parent 68c3cf544f
commit 067f9b5a6f
7 changed files with 61 additions and 58 deletions

View file

@ -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 {

View file

@ -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));
}
}

View file

@ -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);
}

View file

@ -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)]

View file

@ -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

View file

@ -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.

View file

@ -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
}
}