Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/semantics.rs')
| -rw-r--r-- | crates/hir/src/semantics.rs | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index a9af26aa3f..ccbfd45e30 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -10,6 +10,7 @@ use std::{ ops::{self, ControlFlow, Not}, }; +use base_db::FxIndexSet; use either::Either; use hir_def::{ DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId, @@ -2197,7 +2198,7 @@ impl<'db> SemanticsImpl<'db> { &self, element: Either<&ast::Expr, &ast::StmtList>, text_range: TextRange, - ) -> Option<Vec<Local>> { + ) -> Option<FxIndexSet<Local>> { let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; let store = sa.store()?; let mut resolver = sa.resolver.clone(); @@ -2245,31 +2246,49 @@ impl<'db> SemanticsImpl<'db> { let mut exprs: Vec<_> = exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect(); - let mut locals: Vec<Local> = Vec::new(); - let mut add_to_locals_used = |expr_id| { - if let Expr::Path(path) = &store[expr_id] + let mut locals: FxIndexSet<Local> = FxIndexSet::default(); + let mut add_to_locals_used = |id, parent_expr| { + let path = match id { + ExprOrPatId::ExprId(expr_id) => { + if let Expr::Path(path) = &store[expr_id] { + Some(path) + } else { + None + } + } + ExprOrPatId::PatId(pat_id) => { + if let Pat::Path(path) = &store[pat_id] { + Some(path) + } else { + None + } + } + }; + + if let Some(path) = path && is_not_generated(path) { - let _ = resolver.update_to_inner_scope(self.db, def, expr_id); - resolver - .resolve_path_in_value_ns_fully(self.db, path, store.expr_path_hygiene(expr_id)) - .inspect(|value| { - if let ValueNs::LocalBinding(id) = value { - locals.push((def, *id).into()); - } - }); + let _ = resolver.update_to_inner_scope(self.db, def, parent_expr); + let hygiene = store.expr_or_pat_path_hygiene(id); + resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).inspect(|value| { + if let ValueNs::LocalBinding(id) = value { + locals.insert((def, *id).into()); + } + }); } }; while let Some(expr_id) = exprs.pop() { - let mut has_child = false; + if let Expr::Assignment { target, .. } = store[expr_id] { + store.walk_pats(target, &mut |id| { + add_to_locals_used(ExprOrPatId::PatId(id), expr_id) + }); + }; store.walk_child_exprs(expr_id, |id| { - has_child = true; exprs.push(id); }); - if !has_child { - add_to_locals_used(expr_id) - } + + add_to_locals_used(ExprOrPatId::ExprId(expr_id), expr_id) } Some(locals) |