Skip to content

Commit

Permalink
refcator(js_semantic): identify declaration with indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos committed Jul 10, 2024
1 parent 08f0c8f commit 427b4e1
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 94 deletions.
84 changes: 47 additions & 37 deletions crates/biome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use biome_js_syntax::{
TsTypeParameterName,
};
use biome_js_syntax::{AnyJsImportClause, AnyJsNamedImportSpecifier, AnyTsType};
use biome_rowan::TextSize;
use biome_rowan::{syntax::Preorder, AstNode, SyntaxNodeOptionExt, TokenText};
use rustc_hash::FxHashMap;
use std::collections::VecDeque;
Expand Down Expand Up @@ -34,7 +33,7 @@ pub enum SemanticEvent {
/// - All reference identifiers
Read {
range: TextRange,
declaration_at: TextSize,
declaration_id: u32,
scope_id: u32,
},

Expand All @@ -43,7 +42,7 @@ pub enum SemanticEvent {
/// - All reference identifiers
HoistedRead {
range: TextRange,
declaration_at: TextSize,
declaration_id: u32,
scope_id: u32,
},

Expand All @@ -52,7 +51,7 @@ pub enum SemanticEvent {
/// - All identifier assignments
Write {
range: TextRange,
declaration_at: TextSize,
declaration_id: u32,
scope_id: u32,
},

Expand All @@ -62,7 +61,7 @@ pub enum SemanticEvent {
/// - All identifier assignments
HoistedWrite {
range: TextRange,
declaration_at: TextSize,
declaration_id: u32,
scope_id: u32,
},

Expand All @@ -78,7 +77,6 @@ pub enum SemanticEvent {
ScopeStarted {
/// Scope range
range: TextRange,
scope_id: u32,
parent_scope_id: Option<u32>,
is_closure: bool,
},
Expand All @@ -97,7 +95,7 @@ pub enum SemanticEvent {
/// The range points to the binding that is being exported.
Export {
range: TextRange,
declaration_at: TextSize,
declaration_id: u32,
},
}

Expand Down Expand Up @@ -157,10 +155,13 @@ pub struct SemanticEventExtractor {
/// Number of generated scopes
/// This allows assigning a unique id to every scope.
scope_count: u32,
/// Number of declarations.
/// This allows assigning a unique id to every declaration.
declaration_count: u32,
/// At any point this is the set of available bindings and their range in the current scope
bindings: FxHashMap<BindingName, BindingInfo>,
/// Type parameters bound in a `infer T` clause.
infers: Vec<TsTypeParameterName>,
infers: Vec<(TsTypeParameterName, u32)>,
}

/// A binding name is either a type or a value.
Expand Down Expand Up @@ -188,19 +189,13 @@ impl BindingName {
struct BindingInfo {
/// range of the name
range: TextRange,
declaration_id: u32,
/// Kind of the declaration,
/// or in the acse of a bogus declaration, the kind of the name
declaration_kind: JsSyntaxKind,
}

impl BindingInfo {
fn new(range: TextRange, declaration_kind: JsSyntaxKind) -> Self {
Self {
range,
declaration_kind,
}
}

fn is_imported(&self) -> bool {
matches!(
self.declaration_kind,
Expand Down Expand Up @@ -393,11 +388,16 @@ impl SemanticEventExtractor {

fn enter_identifier_binding(&mut self, node: &AnyJsIdentifierBinding) {
let mut hoisted_scope_id = None;
let declaration_id = self.declaration_count;
self.declaration_count += 1;
let is_exported = if let Ok(name_token) = node.name_token() {
let name = name_token.token_text_trimmed();
if let Some(declaration) = node.declaration() {
let info =
BindingInfo::new(name_token.text_trimmed_range(), declaration.syntax().kind());
let info = BindingInfo {
range: name_token.text_trimmed_range(),
declaration_id,
declaration_kind: declaration.syntax().kind(),
};
let is_exported = declaration.export().is_some();
match declaration {
AnyJsBindingDeclaration::JsArrayBindingPatternElement(_)
Expand Down Expand Up @@ -524,15 +524,21 @@ impl SemanticEventExtractor {
AnyJsBindingDeclaration::TsInferType(_) => {
// Delay the declaration of parameter types that are inferred.
// Their scope corresponds to the true branch of the conditional type.
self.infers
.push(TsTypeParameterName::unwrap_cast(node.syntax().clone()));
self.infers.push((
TsTypeParameterName::unwrap_cast(node.syntax().clone()),
declaration_id,
));
return;
}
}
is_exported
} else {
// Handle identifiers in bogus nodes
let info = BindingInfo::new(name_token.text_trimmed_range(), node.syntax().kind());
let info = BindingInfo {
range: name_token.text_trimmed_range(),
declaration_id,
declaration_kind: node.syntax().kind(),
};
self.push_binding(None, BindingName::Value(name), info);
false
}
Expand All @@ -550,7 +556,7 @@ impl SemanticEventExtractor {
if is_exported {
self.stash.push_back(SemanticEvent::Export {
range,
declaration_at: range.start(),
declaration_id,
});
}
}
Expand Down Expand Up @@ -763,11 +769,15 @@ impl SemanticEventExtractor {

fn push_infers_in_scope(&mut self) {
let infers = mem::take(&mut self.infers);
for infer in infers {
for (infer, declaration_id) in infers {
if let Ok(name_token) = infer.ident_token() {
let name = name_token.token_text_trimmed();
let name_range = name_token.text_trimmed_range();
let binding_info = BindingInfo::new(name_range, JsSyntaxKind::TS_INFER_TYPE);
let binding_info = BindingInfo {
range: name_range,
declaration_id,
declaration_kind: JsSyntaxKind::TS_INFER_TYPE,
};
self.push_binding(None, BindingName::Type(name), binding_info);
let scope_id = self.current_scope_mut().scope_id;
self.stash.push_back(SemanticEvent::DeclarationFound {
Expand All @@ -784,7 +794,6 @@ impl SemanticEventExtractor {
self.scope_count += 1;
self.stash.push_back(SemanticEvent::ScopeStarted {
range,
scope_id,
parent_scope_id: self.scopes.iter().last().map(|x| x.scope_id),
is_closure,
});
Expand Down Expand Up @@ -812,28 +821,29 @@ impl SemanticEventExtractor {
if let Some(&BindingInfo {
range: declaration_range,
declaration_kind,
declaration_id,
}) = self.bindings.get(&name)
{
let declaration_at = declaration_range.start();
// We know the declaration of these reference.
for reference in references {
let declaration_before_reference = declaration_at < reference.range().start();
let declaration_before_reference =
declaration_range.start() < reference.range().start();
let event = match reference {
Reference::Export(range) => {
self.stash.push_back(SemanticEvent::Export {
range,
declaration_at,
declaration_id,
});
if declaration_before_reference {
SemanticEvent::Read {
range,
declaration_at,
declaration_id,
scope_id,
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
declaration_id,
scope_id,
}
}
Expand All @@ -856,13 +866,13 @@ impl SemanticEventExtractor {
if declaration_before_reference {
SemanticEvent::Read {
range,
declaration_at,
declaration_id,
scope_id,
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
declaration_id,
scope_id,
}
}
Expand All @@ -871,13 +881,13 @@ impl SemanticEventExtractor {
if declaration_before_reference {
SemanticEvent::Write {
range,
declaration_at,
declaration_id,
scope_id,
}
} else {
SemanticEvent::HoistedWrite {
range,
declaration_at,
declaration_id,
scope_id,
}
}
Expand Down Expand Up @@ -906,19 +916,19 @@ impl SemanticEventExtractor {
Reference::AmbientRead(range) if info.is_imported() => {
// An ambient read can only read a value,
// but also an imported value as a type (with the `type` modifier)
let declaration_at = info.range.start();
let declaration_id = info.declaration_id;
let declaration_before_reference =
declaration_at < reference.range().start();
info.range.start() < reference.range().start();
let event = if declaration_before_reference {
SemanticEvent::Read {
range,
declaration_at,
declaration_id,
scope_id: 0,
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
declaration_id,
scope_id: 0,
}
};
Expand Down
Loading

0 comments on commit 427b4e1

Please sign in to comment.