diff --git a/crates/analysis/src/symbol_analysis/symbol_table/iter.rs b/crates/analysis/src/symbol_analysis/symbol_table/iter.rs index 7de7221..1045bbf 100644 --- a/crates/analysis/src/symbol_analysis/symbol_table/iter.rs +++ b/crates/analysis/src/symbol_analysis/symbol_table/iter.rs @@ -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) } @@ -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(()) @@ -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), @@ -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)), @@ -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 { - value.try_as_member_var_ref().ok_or(()) - } -} - impl<'a> ChildrenSymbolsFilter<'a> for StructSymbol { type ChildRef = &'a MemberVarSymbol; } @@ -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 + Send + 'st>, - local_source_path: PathBuf + iter: Box + 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) } } } @@ -306,42 +301,34 @@ impl<'st> Iterator for FileSymbols<'st> { type Item = &'st SymbolVariant; fn next(&mut self) -> Option { - 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 + 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 } } } @@ -350,8 +337,20 @@ impl<'st> Iterator for SymbolDescendants<'st> { type Item = &'st SymbolVariant; fn next(&mut self) -> Option { - 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 + } } } \ No newline at end of file diff --git a/crates/analysis/src/symbol_analysis/symbol_table/mod.rs b/crates/analysis/src/symbol_analysis/symbol_table/mod.rs index c9b132b..949e1c2 100644 --- a/crates/analysis/src/symbol_analysis/symbol_table/mod.rs +++ b/crates/analysis/src/symbol_analysis/symbol_table/mod.rs @@ -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())); } } @@ -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) } diff --git a/crates/analysis/src/symbol_analysis/symbols/annotated_symbols.rs b/crates/analysis/src/symbol_analysis/symbols/annotated_symbols.rs index 310af7f..92b3f8e 100644 --- a/crates/analysis/src/symbol_analysis/symbols/annotated_symbols.rs +++ b/crates/analysis/src/symbol_analysis/symbols/annotated_symbols.rs @@ -239,7 +239,6 @@ impl WrappedMethodSymbol { } -//FIXME appears twice in document outline /// Corresponding to @addField(Class) vars #[derive(Debug, Clone)] pub struct MemberVarInjectorSymbol { diff --git a/crates/analysis/src/symbol_analysis/symbols/symbol_variant.rs b/crates/analysis/src/symbol_analysis/symbols/symbol_variant.rs index 48d7aef..2ab1314 100644 --- a/crates/analysis/src/symbol_analysis/symbols/symbol_variant.rs +++ b/crates/analysis/src/symbol_analysis/symbols/symbol_variant.rs @@ -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 + } + } } @@ -318,6 +336,15 @@ impl From for SymbolVariant { } } +impl<'a> TryFrom<&'a SymbolVariant> for &'a MemberVarSymbol { + type Error = (); + + fn try_from(value: &'a SymbolVariant) -> Result { + value.try_as_member_var_ref().ok_or(()) + } +} + + impl From for SymbolVariant { fn from(value: AutobindSymbol) -> Self { Self::Autobind(value) diff --git a/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs b/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs index 17e1d48..7ca0f51 100644 --- a/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs +++ b/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs @@ -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()); @@ -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(_) => { } @@ -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()); }, @@ -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()); @@ -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(_)