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 Sep 2, 2024
1 parent 7bcda36 commit c09c99e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 68 deletions.
86 changes: 51 additions & 35 deletions crates/biome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::collections::VecDeque;
use std::mem;
use JsSyntaxKind::*;

use crate::ScopeId;
use crate::{BindingId, ScopeId};

/// Events emitted by the [SemanticEventExtractor].
/// These events are later made into the Semantic Model.
Expand All @@ -36,7 +36,7 @@ pub enum SemanticEvent {
/// - All reference identifiers
Read {
range: TextRange,
declaration_at: TextSize,
declaration_id: BindingId,
scope_id: ScopeId,
},

Expand All @@ -45,7 +45,7 @@ pub enum SemanticEvent {
/// - All reference identifiers
HoistedRead {
range: TextRange,
declaration_at: TextSize,
declaration_id: BindingId,
scope_id: ScopeId,
},

Expand All @@ -54,7 +54,7 @@ pub enum SemanticEvent {
/// - All identifier assignments
Write {
range: TextRange,
declaration_at: TextSize,
declaration_id: BindingId,
scope_id: ScopeId,
},

Expand All @@ -64,7 +64,7 @@ pub enum SemanticEvent {
/// - All identifier assignments
HoistedWrite {
range: TextRange,
declaration_at: TextSize,
declaration_id: BindingId,
scope_id: ScopeId,
},

Expand Down Expand Up @@ -93,7 +93,8 @@ pub enum SemanticEvent {
/// Tracks where a symbol is exported.
Export {
range: TextRange,
declaration_at: TextSize,
declaration_id: BindingId,
declaration_start: TextSize,
},
}

Expand Down Expand Up @@ -153,10 +154,13 @@ pub struct SemanticEventExtractor {
/// Number of generated scopes
/// This allows assigning a unique id to every scope.
scope_count: usize,
/// Number of declarations.
/// This allows assigning a unique id to every declaration.
declaration_count: usize,
/// 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, BindingId)>,
}

/// A binding name is either a type or a value.
Expand Down Expand Up @@ -184,19 +188,13 @@ impl BindingName {
struct BindingInfo {
/// range of the name
range: TextRange,
declaration_id: BindingId,
/// Kind of the declaration,
/// or in the case 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 @@ -452,11 +450,16 @@ impl SemanticEventExtractor {

fn enter_identifier_binding(&mut self, node: &AnyJsIdentifierBinding) {
let mut hoisted_scope_id = None;
let declaration_id = BindingId::new(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 @@ -594,15 +597,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 @@ -620,7 +629,8 @@ impl SemanticEventExtractor {
if is_exported {
self.stash.push_back(SemanticEvent::Export {
range,
declaration_at: range.start(),
declaration_id,
declaration_start: range.start(),
});
}
}
Expand Down Expand Up @@ -833,11 +843,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 Down Expand Up @@ -892,28 +906,30 @@ 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,
declaration_start: declaration_range.start(),
});
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 @@ -936,13 +952,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 @@ -951,13 +967,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 @@ -986,19 +1002,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: ScopeId::new(0),
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
declaration_id,
scope_id: ScopeId::new(0),
}
};
Expand Down
47 changes: 25 additions & 22 deletions crates/biome_js_semantic/src/semantic_model/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,11 @@ impl SemanticModelBuilder {
}
Read {
range,
declaration_at,
declaration_id,
scope_id,
} => {
let binding_id = self.bindings_by_start[&declaration_at];
let binding = &mut self.bindings[binding_id.index()];
let reference_id = ReferenceId::new(binding_id, binding.references.len());
let binding = &mut self.bindings[declaration_id.index()];
let reference_id = ReferenceId::new(declaration_id, binding.references.len());
binding.references.push(SemanticModelReference {
range_start: range.start(),
ty: SemanticModelReferenceType::Read { hoisted: false },
Expand All @@ -212,16 +211,16 @@ impl SemanticModelBuilder {
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(reference_id);

self.declared_at_by_start.insert(range.start(), binding_id);
self.declared_at_by_start
.insert(range.start(), declaration_id);
}
HoistedRead {
range,
declaration_at,
declaration_id,
scope_id,
} => {
let binding_id = self.bindings_by_start[&declaration_at];
let binding = &mut self.bindings[binding_id.index()];
let reference_id = ReferenceId::new(binding_id, binding.references.len());
let binding = &mut self.bindings[declaration_id.index()];
let reference_id = ReferenceId::new(declaration_id, binding.references.len());
binding.references.push(SemanticModelReference {
range_start: range.start(),
ty: SemanticModelReferenceType::Read { hoisted: true },
Expand All @@ -230,16 +229,16 @@ impl SemanticModelBuilder {
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(reference_id);

self.declared_at_by_start.insert(range.start(), binding_id);
self.declared_at_by_start
.insert(range.start(), declaration_id);
}
Write {
range,
declaration_at,
declaration_id,
scope_id,
} => {
let binding_id = self.bindings_by_start[&declaration_at];
let binding = &mut self.bindings[binding_id.index()];
let reference_id = ReferenceId::new(binding_id, binding.references.len());
let binding = &mut self.bindings[declaration_id.index()];
let reference_id = ReferenceId::new(declaration_id, binding.references.len());
binding.references.push(SemanticModelReference {
range_start: range.start(),
ty: SemanticModelReferenceType::Write { hoisted: false },
Expand All @@ -248,16 +247,16 @@ impl SemanticModelBuilder {
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(reference_id);

self.declared_at_by_start.insert(range.start(), binding_id);
self.declared_at_by_start
.insert(range.start(), declaration_id);
}
HoistedWrite {
range,
declaration_at,
declaration_id,
scope_id,
} => {
let binding_id = self.bindings_by_start[&declaration_at];
let binding = &mut self.bindings[binding_id.index()];
let reference_id = ReferenceId::new(binding_id, binding.references.len());
let binding = &mut self.bindings[declaration_id.index()];
let reference_id = ReferenceId::new(declaration_id, binding.references.len());
binding.references.push(SemanticModelReference {
range_start: range.start(),
ty: SemanticModelReferenceType::Write { hoisted: true },
Expand All @@ -266,7 +265,8 @@ impl SemanticModelBuilder {
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(reference_id);

self.declared_at_by_start.insert(range.start(), binding_id);
self.declared_at_by_start
.insert(range.start(), declaration_id);
}
UnresolvedReference { is_read, range } => {
let ty = if is_read {
Expand Down Expand Up @@ -307,8 +307,11 @@ impl SemanticModelBuilder {
.push(SemanticModelUnresolvedReference { range }),
}
}
Export { declaration_at, .. } => {
self.exported.insert(declaration_at);
Export {
declaration_start: declaration_range_start,
..
} => {
self.exported.insert(declaration_range_start);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/biome_js_semantic/src/semantic_model/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::*;
use biome_js_syntax::{AnyJsFunction, AnyJsRoot};

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub(crate) struct BindingId(u32);
pub struct BindingId(u32);

impl BindingId {
pub(crate) fn new(index: usize) -> Self {
Expand Down
Loading

0 comments on commit c09c99e

Please sign in to comment.