From 56b7ea641349f00e1f6b2dc10774bc891fd2a191 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 8 Jul 2024 12:36:35 -0300 Subject: [PATCH] lsp rename/find-all-references for local variables --- compiler/noirc_frontend/src/elaborator/patterns.rs | 6 ++++++ compiler/noirc_frontend/src/elaborator/statements.rs | 6 +++++- compiler/noirc_frontend/src/locations.rs | 1 + compiler/noirc_frontend/src/node_interner.rs | 8 ++++++++ tooling/lsp/src/requests/goto_definition.rs | 5 +++++ tooling/lsp/src/requests/rename.rs | 5 +++++ tooling/lsp/test_programs/local_variable/Nargo.toml | 6 ++++++ tooling/lsp/test_programs/local_variable/src/main.nr | 5 +++++ 8 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tooling/lsp/test_programs/local_variable/Nargo.toml create mode 100644 tooling/lsp/test_programs/local_variable/src/main.nr diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 65627741fb7..2abb453778d 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -438,6 +438,7 @@ impl<'context> Elaborator<'context> { // Otherwise, then it is referring to an Identifier // This lookup allows support of such statements: let x = foo::bar::SOME_GLOBAL + 10; // If the expression is a singular indent, we search the resolver's current scope as normal. + let span = path.span(); let is_self_type_name = path.last_segment().is_self_type_name(); let (hir_ident, var_scope_index) = self.get_ident_from_path(path); @@ -479,6 +480,11 @@ impl<'context> Elaborator<'context> { DefinitionKind::Local(_) => { // only local variables can be captured by closures. self.resolve_local_variable(hir_ident.clone(), var_scope_index); + + let referenced = ReferenceId::Local(hir_ident.id); + let reference = + ReferenceId::Reference(Location::new(span, self.file), false); + self.interner.add_reference(referenced, reference); } } } diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index 8d97bd1a25d..3af73b5d52e 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -16,7 +16,7 @@ use crate::{ macros_api::{ ForLoopStatement, ForRange, HirStatement, LetStatement, Path, Statement, StatementKind, }, - node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, + node_interner::{DefinitionId, DefinitionKind, GlobalId, ReferenceId, StmtId}, Type, }; @@ -256,6 +256,10 @@ impl<'context> Elaborator<'context> { typ.follow_bindings() }; + let referenced = ReferenceId::Local(ident.id); + let reference = ReferenceId::Reference(Location::new(span, self.file), false); + self.interner.add_reference(referenced, reference); + (HirLValue::Ident(ident.clone(), typ.clone()), typ, mutable) } LValue::MemberAccess { object, field_name, span } => { diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index aac1fa2f9f6..fcaef0a8dd6 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -48,6 +48,7 @@ impl NodeInterner { let alias_type = alias_type.borrow(); Location::new(alias_type.name.span(), alias_type.location.file) } + ReferenceId::Local(id) => self.definition(id).location, ReferenceId::Reference(location, _) => location, } } diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 5793922b9b7..588b56afa1a 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -245,6 +245,7 @@ pub enum ReferenceId { Global(GlobalId), Function(FuncId), Alias(TypeAliasId), + Local(DefinitionId), Reference(Location, bool /* is Self */), } @@ -836,12 +837,19 @@ impl NodeInterner { location: Location, ) -> DefinitionId { let id = DefinitionId(self.definitions.len()); + let is_local = matches!(definition, DefinitionKind::Local(_)); + if let DefinitionKind::Function(func_id) = definition { self.function_definition_ids.insert(func_id, id); } let kind = definition; self.definitions.push(DefinitionInfo { name, mutable, comptime, kind, location }); + + if is_local { + self.add_definition_location(ReferenceId::Local(id)); + } + id } diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index fe591a433cf..3713e8b646a 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -196,4 +196,9 @@ mod goto_definition_tests { ) .await; } + + #[test] + async fn goto_for_local_variable() { + expect_goto_for_all_references("local_variable", "some_var", 0).await; + } } diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index db3d6091cae..ac6c6792e15 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -194,4 +194,9 @@ mod rename_tests { async fn test_rename_global() { check_rename_succeeds("rename_global", "FOO").await; } + + #[test] + async fn test_rename_local_variable() { + check_rename_succeeds("local_variable", "some_var").await; + } } diff --git a/tooling/lsp/test_programs/local_variable/Nargo.toml b/tooling/lsp/test_programs/local_variable/Nargo.toml new file mode 100644 index 00000000000..df881fb5f4d --- /dev/null +++ b/tooling/lsp/test_programs/local_variable/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "local_variable" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/local_variable/src/main.nr b/tooling/lsp/test_programs/local_variable/src/main.nr new file mode 100644 index 00000000000..e41cbed085f --- /dev/null +++ b/tooling/lsp/test_programs/local_variable/src/main.nr @@ -0,0 +1,5 @@ +fn main() { + let mut some_var = 1; + some_var = 2; + let _ = some_var; +}