Skip to content

Commit

Permalink
fixed symbol table iterators
Browse files Browse the repository at this point in the history
1. Added missing symbol types to `symbol_children` iterators
1. Fixed `FileSymbols` repeating annotated symbols
  • Loading branch information
SpontanCombust committed Aug 22, 2024
1 parent 7e15b56 commit 0eb9bc5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 49 deletions.
89 changes: 44 additions & 45 deletions crates/analysis/src/symbol_analysis/symbol_table/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ pub trait ChildrenSymbolsFilter<'a>: Symbol {
pub enum ClassSymbolChild<'st> {
Var(&'st MemberVarSymbol),
Autobind(&'st AutobindSymbol),
VarInjector(&'st MemberVarInjectorSymbol),
Method(&'st MemberFunctionSymbol),
Event(&'st EventSymbol),
MethodInjector(&'st MemberFunctionInjectorSymbol),
ThisVar(&'st ThisVarSymbol),
SuperVar(&'st SuperVarSymbol)
}
Expand All @@ -80,8 +82,10 @@ impl<'a> TryFrom<&'a SymbolVariant> for ClassSymbolChild<'a> {
match value {
SymbolVariant::MemberVar(s) => Ok(ClassSymbolChild::Var(s)),
SymbolVariant::Autobind(s) => Ok(ClassSymbolChild::Autobind(s)),
SymbolVariant::MemberVarInjector(s) => Ok(ClassSymbolChild::VarInjector(s)),
SymbolVariant::MemberFunc(s) => Ok(ClassSymbolChild::Method(s)),
SymbolVariant::Event(s) => Ok(ClassSymbolChild::Event(s)),
SymbolVariant::MemberFuncInjector(s) => Ok(ClassSymbolChild::MethodInjector(s)),
SymbolVariant::ThisVar(s) => Ok(ClassSymbolChild::ThisVar(s)),
SymbolVariant::SuperVar(s) => Ok(ClassSymbolChild::SuperVar(s)),
_ => Err(())
Expand All @@ -97,8 +101,10 @@ impl<'a> ChildrenSymbolsFilter<'a> for ClassSymbol {
pub enum StateSymbolChild<'st> {
Var(&'st MemberVarSymbol),
Autobind(&'st AutobindSymbol),
VarInjector(&'st MemberVarInjectorSymbol),
Method(&'st MemberFunctionSymbol),
Event(&'st EventSymbol),
MethodInjector(&'st MemberFunctionInjectorSymbol),
ThisVar(&'st ThisVarSymbol),
SuperVar(&'st SuperVarSymbol),
ParentVar(&'st ParentVarSymbol),
Expand All @@ -112,8 +118,10 @@ impl<'a> TryFrom<&'a SymbolVariant> for StateSymbolChild<'a> {
match value {
SymbolVariant::MemberVar(s) => Ok(StateSymbolChild::Var(s)),
SymbolVariant::Autobind(s) => Ok(StateSymbolChild::Autobind(s)),
SymbolVariant::MemberVarInjector(s) => Ok(StateSymbolChild::VarInjector(s)),
SymbolVariant::MemberFunc(s) => Ok(StateSymbolChild::Method(s)),
SymbolVariant::Event(s) => Ok(StateSymbolChild::Event(s)),
SymbolVariant::MemberFuncInjector(s) => Ok(StateSymbolChild::MethodInjector(s)),
SymbolVariant::ThisVar(s) => Ok(StateSymbolChild::ThisVar(s)),
SymbolVariant::SuperVar(s) => Ok(StateSymbolChild::SuperVar(s)),
SymbolVariant::ParentVar(s) => Ok(StateSymbolChild::ParentVar(s)),
Expand All @@ -128,14 +136,6 @@ impl<'a> ChildrenSymbolsFilter<'a> for StateSymbol {
}


impl<'a> TryFrom<&'a SymbolVariant> for &'a MemberVarSymbol {
type Error = ();

fn try_from(value: &'a SymbolVariant) -> Result<Self, Self::Error> {
value.try_as_member_var_ref().ok_or(())
}
}

impl<'a> ChildrenSymbolsFilter<'a> for StructSymbol {
type ChildRef = &'a MemberVarSymbol;
}
Expand Down Expand Up @@ -278,26 +278,21 @@ impl<'st> Iterator for FilePrimarySymbols<'st> {

/// Iterate over symbols associated with a script file at a given path
pub struct FileSymbols<'st> {
iter: Box<dyn Iterator<Item = &'st SymbolVariant> + Send + 'st>,
local_source_path: PathBuf
iter: Box<dyn Iterator<Item = &'st SymbolVariant> + Send + 'st>
}

impl<'st> FileSymbols<'st> {
pub(super) fn new(symtab: &'st SymbolTable, local_source_path: &Path) -> Self {
let roots = symtab.source_path_assocs
.get(local_source_path)
.map(|v| v.as_slice())
.unwrap_or_default();

let iter = roots.iter()
.map(|root| symtab.symbols.range(root.to_owned()..)
.take_while(|(p, _)| p.starts_with(root))
.map(|(_, v)| v))
let iter =
symtab.get_primary_symbols_for_source(local_source_path)
.map(|prim_sym| {
std::iter::once(prim_sym)
.chain(symtab.get_symbol_descendants(prim_sym.path_ref(), true))
})
.flatten();

Self {
iter: Box::new(iter),
local_source_path: local_source_path.to_owned()
iter: Box::new(iter)
}
}
}
Expand All @@ -306,42 +301,34 @@ impl<'st> Iterator for FileSymbols<'st> {
type Item = &'st SymbolVariant;

fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.iter.next() {
// Normally all symbols under one parent path are associated with the same source path.
// Symbols created using annotations are an exception to this.
// Their symbol paths can reference symbols from other source paths.
// We have to skip over them and all of their children.
if item.location().map(|loc| loc.local_source_path.as_ref() != self.local_source_path).unwrap_or(false) {
let injector_path = item.path_ref().to_owned();
self.iter.find(|v| !v.path_ref().starts_with(&injector_path))
} else {
Some(item)
}
} else {
None
}
self.iter.next()
}
}


/// Iterator of all symbols descending from a given parent symbol.
/// If you want an iterator going over only direct children use [`SymbolChildren`].
#[derive(Clone)]
pub struct SymbolDescendants<'st> {
iter: btree_map::Range<'st, SymbolPathBuf, SymbolVariant>,
parent_sympath: SymbolPathBuf
iter: Box<dyn Iterator<Item = &'st SymbolVariant> + Send + 'st>,
skip_primary_children: bool
}

impl<'st> SymbolDescendants<'st> {
pub(super) fn new(symtab: &'st SymbolTable, sympath: &SymbolPath) -> Self {
let mut iter = symtab.symbols.range(sympath.to_owned()..);
pub(super) fn new(symtab: &'st SymbolTable, sympath: &SymbolPath, skip_primary_children: bool) -> Self {
let parent_sympath = sympath.to_owned();

let mut iter = symtab.symbols
.range(sympath.to_owned()..)
.take_while(move |(sympath, _)| sympath.starts_with(&parent_sympath))
.map(|(_, symvar)| symvar);

// prime the iterator to go to the first descendant
// it is assumed this parent exists
iter.next();

Self {
iter,
parent_sympath: sympath.to_owned()
iter: Box::new(iter),
skip_primary_children
}
}
}
Expand All @@ -350,8 +337,20 @@ impl<'st> Iterator for SymbolDescendants<'st> {
type Item = &'st SymbolVariant;

fn next(&mut self) -> Option<Self::Item> {
self.iter
.find(|(sympath, _)| sympath.starts_with(&self.parent_sympath))
.map(|(_, variant)| variant)
if let Some(mut item) = self.iter.next() {
while self.skip_primary_children && item.is_primary() {
let prim_item_sympath = item.path_ref().to_owned();

if let Some(skipped) = self.iter.find(move |v| !v.path_ref().starts_with(&prim_item_sympath)) {
item = skipped;
} else {
return None;
}
}

Some(item)
} else {
None
}
}
}
9 changes: 6 additions & 3 deletions crates/analysis/src/symbol_analysis/symbol_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl SymbolTable {
for (array_sympath, refs) in self.array_type_refs.iter() {
if refs.is_empty() {
for_removal.push(array_sympath.to_owned());
for_removal.extend(self.get_symbol_descendants(&array_sympath).map(|v| v.path_ref().to_owned()));
for_removal.extend(self.get_symbol_descendants(&array_sympath, false).map(|v| v.path_ref().to_owned()));
}
}

Expand Down Expand Up @@ -175,9 +175,12 @@ impl SymbolTable {

/// Iterate over all descendants of a symbol in a symbol hierarchy.
/// Symbols are returned ordered by their symbol path.
///
/// - skip_primary_children - if children symbols that do not attach themselves naturally to the symbol hierarchy should be skipped.
/// Refers to annotated symbols that exist outside of classes' bodies, but their paths still have the class as a parent.
#[inline]
pub fn get_symbol_descendants<'a>(&'a self, path: &SymbolPath) -> SymbolDescendants<'a> {
SymbolDescendants::new(self, path)
pub fn get_symbol_descendants<'a>(&'a self, path: &SymbolPath, skip_primary_children: bool) -> SymbolDescendants<'a> {
SymbolDescendants::new(self, path, skip_primary_children)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ impl WrappedMethodSymbol {
}


//FIXME appears twice in document outline
/// Corresponding to @addField(Class) vars
#[derive(Debug, Clone)]
pub struct MemberVarInjectorSymbol {
Expand Down
27 changes: 27 additions & 0 deletions crates/analysis/src/symbol_analysis/symbols/symbol_variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,24 @@ impl SymbolVariant {
Self::WrappedMethod(_) => None,
}
}

pub fn is_primary(&self) -> bool {
match self {
SymbolVariant::Class(_)
| SymbolVariant::State(_)
| SymbolVariant::Struct(_)
| SymbolVariant::Enum(_)
| SymbolVariant::EnumVariant(_)
| SymbolVariant::GlobalFunc(_)
| SymbolVariant::Constructor(_)
| SymbolVariant::MemberFuncInjector(_)
| SymbolVariant::MemberFuncReplacer(_)
| SymbolVariant::GlobalFuncReplacer(_)
| SymbolVariant::MemberFuncWrapper(_)
| SymbolVariant::MemberVarInjector(_) => true,
_ => false
}
}
}


Expand Down Expand Up @@ -318,6 +336,15 @@ impl From<MemberVarSymbol> for SymbolVariant {
}
}

impl<'a> TryFrom<&'a SymbolVariant> for &'a MemberVarSymbol {
type Error = ();

fn try_from(value: &'a SymbolVariant) -> Result<Self, Self::Error> {
value.try_as_member_var_ref().ok_or(())
}
}


impl From<AutobindSymbol> for SymbolVariant {
fn from(value: AutobindSymbol) -> Self {
Self::Autobind(value)
Expand Down
30 changes: 30 additions & 0 deletions crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ impl<'a> UnqualifiedNameLookupBuilder<'a> {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::VarInjector(s) => {
if class.path_ref() == class_path || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::Method(s) => {
if class.path_ref() == class_path || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
Expand All @@ -217,6 +222,11 @@ impl<'a> UnqualifiedNameLookupBuilder<'a> {
ClassSymbolChild::Event(s) => {
unl.insert(s.path_ref().to_owned());
},
ClassSymbolChild::MethodInjector(s) => {
if class.path_ref() == class_path || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
// these are special reserved names, they cannot be overshadowed
ClassSymbolChild::ThisVar(_)
| ClassSymbolChild::SuperVar(_) => { }
Expand Down Expand Up @@ -269,11 +279,21 @@ impl SyntaxNodeVisitor for UnqualifiedNameLookupBuilder<'_> {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::VarInjector(s) => {
if !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::Method(s) => {
if !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::MethodInjector(s) => {
if !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
ClassSymbolChild::Event(s) => {
unl.insert(s.path_ref().to_owned());
},
Expand Down Expand Up @@ -305,6 +325,11 @@ impl SyntaxNodeVisitor for UnqualifiedNameLookupBuilder<'_> {
unl.insert(s.path_ref().to_owned());
}
},
StateSymbolChild::VarInjector(s) => {
if state.path_ref() == &sympath_ctx.current_sympath || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
StateSymbolChild::Method(s) => {
if state.path_ref() == &sympath_ctx.current_sympath || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
Expand All @@ -313,6 +338,11 @@ impl SyntaxNodeVisitor for UnqualifiedNameLookupBuilder<'_> {
StateSymbolChild::Event(s) => {
unl.insert(s.path_ref().to_owned());
},
StateSymbolChild::MethodInjector(s) => {
if state.path_ref() == &sympath_ctx.current_sympath || !s.specifiers.contains(AccessModifier::Private.into()) {
unl.insert(s.path_ref().to_owned());
}
},
// these are special reserved names, they cannot be overshadowed
StateSymbolChild::ThisVar(_)
| StateSymbolChild::SuperVar(_)
Expand Down

0 comments on commit 0eb9bc5

Please sign in to comment.