mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(semantic): move redeclare varaibles to symbol table (#2614)
close: #2219
This commit is contained in:
parent
798a6dfe46
commit
57ce737b09
5 changed files with 30 additions and 51 deletions
|
|
@ -7,7 +7,6 @@ use oxc_diagnostics::{
|
||||||
thiserror::{self, Error},
|
thiserror::{self, Error},
|
||||||
};
|
};
|
||||||
use oxc_macros::declare_oxc_lint;
|
use oxc_macros::declare_oxc_lint;
|
||||||
use oxc_semantic::VariableInfo;
|
|
||||||
use oxc_span::{CompactStr, Span};
|
use oxc_span::{CompactStr, Span};
|
||||||
|
|
||||||
use crate::{context::LintContext, rule::Rule};
|
use crate::{context::LintContext, rule::Rule};
|
||||||
|
|
@ -73,23 +72,27 @@ impl Rule for NoRedeclare {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_once(&self, ctx: &LintContext) {
|
fn run_once(&self, ctx: &LintContext) {
|
||||||
let redeclare_variables = ctx.semantic().redeclare_variables();
|
|
||||||
let symbol_table = ctx.semantic().symbols();
|
let symbol_table = ctx.semantic().symbols();
|
||||||
|
|
||||||
for variable in redeclare_variables {
|
for symbol_id in ctx.symbols().iter() {
|
||||||
let decl = symbol_table.get_declaration(variable.symbol_id);
|
let decl = symbol_table.get_declaration(symbol_id);
|
||||||
|
let symbol_name = symbol_table.get_name(symbol_id);
|
||||||
match ctx.nodes().kind(decl) {
|
match ctx.nodes().kind(decl) {
|
||||||
AstKind::VariableDeclarator(var) => {
|
AstKind::VariableDeclarator(var) => {
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = &var.id.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = &var.id.kind {
|
||||||
if symbol_table.get_name(variable.symbol_id) == ident.name.as_str() {
|
if symbol_name == ident.name.as_str() {
|
||||||
self.report_diagnostic(ctx, variable, ident);
|
for span in ctx.symbols().get_redeclare_variables(symbol_id) {
|
||||||
|
self.report_diagnostic(ctx, *span, ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstKind::FormalParameter(param) => {
|
AstKind::FormalParameter(param) => {
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.pattern.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.pattern.kind {
|
||||||
if symbol_table.get_name(variable.symbol_id) == ident.name.as_str() {
|
if symbol_name == ident.name.as_str() {
|
||||||
self.report_diagnostic(ctx, variable, ident);
|
for span in ctx.symbols().get_redeclare_variables(symbol_id) {
|
||||||
|
self.report_diagnostic(ctx, *span, ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,23 +103,14 @@ impl Rule for NoRedeclare {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoRedeclare {
|
impl NoRedeclare {
|
||||||
fn report_diagnostic(
|
fn report_diagnostic(&self, ctx: &LintContext, span: Span, ident: &BindingIdentifier) {
|
||||||
&self,
|
|
||||||
ctx: &LintContext,
|
|
||||||
variable: &VariableInfo,
|
|
||||||
ident: &BindingIdentifier,
|
|
||||||
) {
|
|
||||||
if self.built_in_globals && ctx.env_contains_var(&ident.name) {
|
if self.built_in_globals && ctx.env_contains_var(&ident.name) {
|
||||||
ctx.diagnostic(NoRedeclareAsBuiltiInDiagnostic(
|
ctx.diagnostic(NoRedeclareAsBuiltiInDiagnostic(
|
||||||
ident.name.to_compact_str(),
|
ident.name.to_compact_str(),
|
||||||
ident.span,
|
ident.span,
|
||||||
));
|
));
|
||||||
} else if variable.span != ident.span {
|
} else {
|
||||||
ctx.diagnostic(NoRedeclareDiagnostic(
|
ctx.diagnostic(NoRedeclareDiagnostic(ident.name.to_compact_str(), ident.span, span));
|
||||||
ident.name.to_compact_str(),
|
|
||||||
ident.span,
|
|
||||||
variable.span,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use oxc_ast::{
|
||||||
};
|
};
|
||||||
use oxc_span::{Atom, SourceType};
|
use oxc_span::{Atom, SourceType};
|
||||||
|
|
||||||
use crate::{scope::ScopeFlags, symbol::SymbolFlags, SemanticBuilder, VariableInfo};
|
use crate::{scope::ScopeFlags, symbol::SymbolFlags, SemanticBuilder};
|
||||||
|
|
||||||
pub trait Binder {
|
pub trait Binder {
|
||||||
fn bind(&self, _builder: &mut SemanticBuilder) {}
|
fn bind(&self, _builder: &mut SemanticBuilder) {}
|
||||||
|
|
@ -59,7 +59,7 @@ impl<'a> Binder for VariableDeclarator<'a> {
|
||||||
builder.check_redeclaration(*scope_id, span, name, excludes, true)
|
builder.check_redeclaration(*scope_id, span, name, excludes, true)
|
||||||
{
|
{
|
||||||
ident.symbol_id.set(Some(symbol_id));
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
builder.add_redeclared_variables(VariableInfo { span: ident.span, symbol_id });
|
builder.add_redeclare_variable(symbol_id, ident.span);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,17 +29,6 @@ use crate::{
|
||||||
Semantic,
|
Semantic,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct VariableInfo {
|
|
||||||
pub span: Span,
|
|
||||||
pub symbol_id: SymbolId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RedeclareVariables {
|
|
||||||
pub variables: Vec<VariableInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SemanticBuilder<'a> {
|
pub struct SemanticBuilder<'a> {
|
||||||
pub source_text: &'a str,
|
pub source_text: &'a str,
|
||||||
|
|
||||||
|
|
@ -79,8 +68,6 @@ pub struct SemanticBuilder<'a> {
|
||||||
|
|
||||||
check_syntax_error: bool,
|
check_syntax_error: bool,
|
||||||
|
|
||||||
redeclare_variables: RedeclareVariables,
|
|
||||||
|
|
||||||
pub cfg: ControlFlowGraph,
|
pub cfg: ControlFlowGraph,
|
||||||
|
|
||||||
pub class_table_builder: ClassTableBuilder,
|
pub class_table_builder: ClassTableBuilder,
|
||||||
|
|
@ -117,7 +104,6 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
label_builder: LabelBuilder::default(),
|
label_builder: LabelBuilder::default(),
|
||||||
jsdoc: JSDocBuilder::new(source_text, &trivias),
|
jsdoc: JSDocBuilder::new(source_text, &trivias),
|
||||||
check_syntax_error: false,
|
check_syntax_error: false,
|
||||||
redeclare_variables: RedeclareVariables { variables: vec![] },
|
|
||||||
cfg: ControlFlowGraph::new(),
|
cfg: ControlFlowGraph::new(),
|
||||||
class_table_builder: ClassTableBuilder::new(),
|
class_table_builder: ClassTableBuilder::new(),
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +163,6 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
module_record: Arc::clone(&self.module_record),
|
module_record: Arc::clone(&self.module_record),
|
||||||
jsdoc: self.jsdoc.build(),
|
jsdoc: self.jsdoc.build(),
|
||||||
unused_labels: self.label_builder.unused_node_ids,
|
unused_labels: self.label_builder.unused_node_ids,
|
||||||
redeclare_variables: self.redeclare_variables.variables,
|
|
||||||
cfg: self.cfg,
|
cfg: self.cfg,
|
||||||
};
|
};
|
||||||
SemanticBuilderReturn { semantic, errors: self.errors.into_inner() }
|
SemanticBuilderReturn { semantic, errors: self.errors.into_inner() }
|
||||||
|
|
@ -195,7 +180,6 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
module_record: Arc::new(ModuleRecord::default()),
|
module_record: Arc::new(ModuleRecord::default()),
|
||||||
jsdoc: self.jsdoc.build(),
|
jsdoc: self.jsdoc.build(),
|
||||||
unused_labels: self.label_builder.unused_node_ids,
|
unused_labels: self.label_builder.unused_node_ids,
|
||||||
redeclare_variables: self.redeclare_variables.variables,
|
|
||||||
cfg: self.cfg,
|
cfg: self.cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,9 +238,7 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
) -> SymbolId {
|
) -> SymbolId {
|
||||||
if let Some(symbol_id) = self.check_redeclaration(scope_id, span, name, excludes, true) {
|
if let Some(symbol_id) = self.check_redeclaration(scope_id, span, name, excludes, true) {
|
||||||
self.symbols.union_flag(symbol_id, includes);
|
self.symbols.union_flag(symbol_id, includes);
|
||||||
if includes.is_function_scoped_declaration() {
|
self.add_redeclare_variable(symbol_id, span);
|
||||||
self.add_redeclared_variables(VariableInfo { span, symbol_id });
|
|
||||||
}
|
|
||||||
return symbol_id;
|
return symbol_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,8 +320,8 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_redeclared_variables(&mut self, variable: VariableInfo) {
|
pub fn add_redeclare_variable(&mut self, symbol_id: SymbolId, span: Span) {
|
||||||
self.redeclare_variables.variables.push(variable);
|
self.symbols.add_redeclare_variable(symbol_id, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_export_flag_for_export_identifier(&mut self) {
|
fn add_export_flag_for_export_identifier(&mut self) {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ pub use oxc_syntax::{
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
builder::VariableInfo,
|
|
||||||
control_flow::{
|
control_flow::{
|
||||||
print_basic_block, AssignmentValue, BasicBlockElement, BinaryAssignmentValue, BinaryOp,
|
print_basic_block, AssignmentValue, BasicBlockElement, BinaryAssignmentValue, BinaryOp,
|
||||||
CallType, CalleeWithArgumentsAssignmentValue, CollectionAssignmentValue, ControlFlowGraph,
|
CallType, CalleeWithArgumentsAssignmentValue, CollectionAssignmentValue, ControlFlowGraph,
|
||||||
|
|
@ -64,8 +63,6 @@ pub struct Semantic<'a> {
|
||||||
|
|
||||||
unused_labels: FxHashSet<AstNodeId>,
|
unused_labels: FxHashSet<AstNodeId>,
|
||||||
|
|
||||||
redeclare_variables: Vec<VariableInfo>,
|
|
||||||
|
|
||||||
cfg: ControlFlowGraph,
|
cfg: ControlFlowGraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,10 +144,6 @@ impl<'a> Semantic<'a> {
|
||||||
pub fn is_reference_to_global_variable(&self, ident: &IdentifierReference) -> bool {
|
pub fn is_reference_to_global_variable(&self, ident: &IdentifierReference) -> bool {
|
||||||
self.scopes().root_unresolved_references().contains_key(ident.name.as_str())
|
self.scopes().root_unresolved_references().contains_key(ident.name.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redeclare_variables(&self) -> &Vec<VariableInfo> {
|
|
||||||
&self.redeclare_variables
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ pub struct SymbolTable {
|
||||||
pub declarations: IndexVec<SymbolId, AstNodeId>,
|
pub declarations: IndexVec<SymbolId, AstNodeId>,
|
||||||
pub resolved_references: IndexVec<SymbolId, Vec<ReferenceId>>,
|
pub resolved_references: IndexVec<SymbolId, Vec<ReferenceId>>,
|
||||||
pub references: IndexVec<ReferenceId, Reference>,
|
pub references: IndexVec<ReferenceId, Reference>,
|
||||||
|
pub redeclare_variables: IndexVec<SymbolId, Vec<Span>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolTable {
|
impl SymbolTable {
|
||||||
|
|
@ -89,6 +90,10 @@ impl SymbolTable {
|
||||||
self.flags[symbol_id]
|
self.flags[symbol_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_redeclare_variables(&self, symbol_id: SymbolId) -> &Vec<Span> {
|
||||||
|
&self.redeclare_variables[symbol_id]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn union_flag(&mut self, symbol_id: SymbolId, includes: SymbolFlags) {
|
pub fn union_flag(&mut self, symbol_id: SymbolId, includes: SymbolFlags) {
|
||||||
self.flags[symbol_id] |= includes;
|
self.flags[symbol_id] |= includes;
|
||||||
}
|
}
|
||||||
|
|
@ -120,13 +125,18 @@ impl SymbolTable {
|
||||||
_ = self.names.push(name.into_compact_str());
|
_ = self.names.push(name.into_compact_str());
|
||||||
_ = self.flags.push(flag);
|
_ = self.flags.push(flag);
|
||||||
_ = self.scope_ids.push(scope_id);
|
_ = self.scope_ids.push(scope_id);
|
||||||
self.resolved_references.push(vec![])
|
_ = self.resolved_references.push(vec![]);
|
||||||
|
self.redeclare_variables.push(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_declaration(&mut self, node_id: AstNodeId) {
|
pub fn add_declaration(&mut self, node_id: AstNodeId) {
|
||||||
self.declarations.push(node_id);
|
self.declarations.push(node_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_redeclare_variable(&mut self, symbol_id: SymbolId, span: Span) {
|
||||||
|
self.redeclare_variables[symbol_id].push(span);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_reference(&mut self, reference: Reference) -> ReferenceId {
|
pub fn create_reference(&mut self, reference: Reference) -> ReferenceId {
|
||||||
self.references.push(reference)
|
self.references.push(reference)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue