diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 9c72529e11a..791cb8913d6 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -27,7 +27,7 @@ use crate::{ HirLiteral, HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression, MethodCallExpression, PrefixExpression, }, - node_interner::{DefinitionKind, ExprId, FuncId}, + node_interner::{DefinitionKind, DependencyId, ExprId, FuncId}, token::Tokens, Kind, QuotedType, Shared, StructType, Type, }; @@ -431,6 +431,11 @@ impl<'context> Elaborator<'context> { r#type, struct_generics, }); + + let referenced = DependencyId::Struct(struct_type.borrow().id); + let reference = DependencyId::Variable(Location::new(span, self.file)); + self.interner.add_reference(referenced, reference); + (expr, Type::Struct(struct_type, generics)) } diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 8a2f305d8f6..94f03fb511b 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -157,6 +157,8 @@ impl<'context> Elaborator<'context> { mutable: Option, new_definitions: &mut Vec, ) -> HirPattern { + let name_span = name.last_segment().span(); + let error_identifier = |this: &mut Self| { // Must create a name here to return a HirPattern::Identifier. Allowing // shadowing here lets us avoid further errors if we define ERROR_IDENT @@ -196,6 +198,10 @@ impl<'context> Elaborator<'context> { new_definitions, ); + let referenced = DependencyId::Struct(struct_type.borrow().id); + let reference = DependencyId::Variable(Location::new(name_span, self.file)); + self.interner.add_reference(referenced, reference); + HirPattern::Struct(expected_type, fields, location) } @@ -584,10 +590,7 @@ impl<'context> Elaborator<'context> { } pub fn get_ident_from_path(&mut self, path: Path) -> (HirIdent, usize) { - let location = Location::new( - path.segments.last().expect("ice: path without segments").span(), - self.file, - ); + let location = Location::new(path.last_segment().span(), self.file); let error = match path.as_ident().map(|ident| self.use_variable(ident)) { Some(Ok(found)) => return found, diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 7f07e2a9538..924950bd0b6 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -30,7 +30,9 @@ use crate::{ HirExpression, HirLiteral, HirStatement, Path, PathKind, SecondaryAttribute, Signedness, UnaryOp, UnresolvedType, UnresolvedTypeData, }, - node_interner::{DefinitionKind, ExprId, GlobalId, TraitId, TraitImplKind, TraitMethodId}, + node_interner::{ + DefinitionKind, DependencyId, ExprId, GlobalId, TraitId, TraitImplKind, TraitMethodId, + }, Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeVariable, TypeVariableKind, }; @@ -242,6 +244,8 @@ impl<'context> Elaborator<'context> { return Type::Alias(alias, args); } + let last_segment = path.last_segment(); + match self.lookup_struct_or_error(path) { Some(struct_type) => { if self.resolving_ids.contains(&struct_type.borrow().id) { @@ -279,6 +283,11 @@ impl<'context> Elaborator<'context> { self.interner.add_type_dependency(current_item, dependency_id); } + let referenced = DependencyId::Struct(struct_type.borrow().id); + let reference = + DependencyId::Variable(Location::new(last_segment.span(), self.file)); + self.interner.add_reference(referenced, reference); + Type::Struct(struct_type, args) } None => Type::Error, diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 6858e10a175..31214e01480 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -483,9 +483,17 @@ fn add_import_reference( // We ignore empty spans at 0 location, this must be Stdlib return; } - if let crate::macros_api::ModuleDefId::FunctionId(func_id) = def_id { - let variable = DependencyId::Variable(Location::new(name.span(), file_id)); - interner.add_reference_for(DependencyId::Function(func_id), variable); + + match def_id { + crate::macros_api::ModuleDefId::FunctionId(func_id) => { + let variable = DependencyId::Variable(Location::new(name.span(), file_id)); + interner.add_reference_for(DependencyId::Function(func_id), variable); + } + crate::macros_api::ModuleDefId::TypeId(struct_id) => { + let variable = DependencyId::Variable(Location::new(name.span(), file_id)); + interner.add_reference_for(DependencyId::Struct(struct_id), variable); + } + _ => (), } } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index aebc649b7b2..935a891170c 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -14,6 +14,7 @@ use crate::ast::{ TypeImpl, }; use crate::macros_api::NodeInterner; +use crate::node_interner::DependencyId; use crate::{ graph::CrateId, hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait}, @@ -267,6 +268,7 @@ impl<'a> ModCollector<'a> { let mut definition_errors = vec![]; for struct_definition in types { let name = struct_definition.name.clone(); + let name_location = Location::new(name.span(), self.file_id); let unresolved = UnresolvedStruct { file_id: self.file_id, @@ -310,6 +312,9 @@ impl<'a> ModCollector<'a> { // And store the TypeId -> StructType mapping somewhere it is reachable self.def_collector.items.types.insert(id, unresolved); + + context.def_interner.add_struct_location(id, name_location); + context.def_interner.add_definition_location(DependencyId::Struct(id)); } definition_errors } diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index 71fdc6b30d2..87c4133d68e 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -290,4 +290,9 @@ impl Context<'_, '_> { ResolvedGeneric { name, type_var, kind, span } }) } + + // Enables reference tracking (useful for tools like LSP). + pub fn track_references(&mut self) { + self.def_interner.track_references = true; + } } diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index dd6a3412a40..b8fa35a1193 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -32,7 +32,7 @@ impl NodeInterner { pub fn dependency_location(&self, dependency: DependencyId) -> Location { match dependency { DependencyId::Function(id) => self.function_modifiers(&id).name_location, - DependencyId::Struct(id) => self.get_struct(id).borrow().location, + DependencyId::Struct(id) => self.struct_location(&id), DependencyId::Global(id) => self.get_global(id).location, DependencyId::Alias(id) => self.get_type_alias(id).borrow().location, DependencyId::Variable(location) => location, @@ -40,6 +40,10 @@ impl NodeInterner { } pub(crate) fn add_reference(&mut self, referenced: DependencyId, reference: DependencyId) { + if !self.track_references { + return; + } + let referenced_index = self.get_or_insert_reference(referenced); let reference_index = self.reference_graph.add_node(reference); @@ -56,6 +60,10 @@ impl NodeInterner { referenced_id: DependencyId, reference: DependencyId, ) { + if !self.track_references { + return; + } + let Some(referenced_index) = self.reference_graph_indices.get(&referenced_id) else { panic!("Compiler Error: Referenced index not found") }; @@ -67,6 +75,10 @@ impl NodeInterner { } pub(crate) fn add_definition_location(&mut self, referenced: DependencyId) { + if !self.track_references { + return; + } + let referenced_index = self.get_or_insert_reference(referenced); let referenced_location = self.dependency_location(referenced); self.location_indices.add_location(referenced_location, referenced_index); @@ -92,8 +104,10 @@ impl NodeInterner { let reference_node = self.reference_graph[node_index]; let found_locations: Vec = match reference_node { - DependencyId::Alias(_) | DependencyId::Struct(_) | DependencyId::Global(_) => todo!(), - DependencyId::Function(_) => self.get_edit_locations(node_index), + DependencyId::Alias(_) | DependencyId::Global(_) => todo!(), + DependencyId::Function(_) | DependencyId::Struct(_) => { + self.get_edit_locations(node_index) + } DependencyId::Variable(_) => { let referenced_node_index = self diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 2cb18a71d7a..5f08bdc0383 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::collections::HashMap; use std::fmt; +use std::hash::Hash; use std::ops::Deref; use fm::FileId; @@ -64,6 +65,9 @@ pub struct NodeInterner { // Contains the source module each function was defined in function_modules: HashMap, + // The location of each struct name + struct_name_locations: HashMap, + /// This graph tracks dependencies between different global definitions. /// This is used to ensure the absence of dependency cycles for globals and types. dependency_graph: DiGraph, @@ -184,6 +188,9 @@ pub struct NodeInterner { /// the actual type since types do not implement Send or Sync. quoted_types: noirc_arena::Arena, + /// Whether to track references. In regular compilations this is false, but tools set it to true. + pub(crate) track_references: bool, + /// Store the location of the references in the graph pub(crate) reference_graph: DiGraph, @@ -504,6 +511,7 @@ impl Default for NodeInterner { function_definition_ids: HashMap::new(), function_modifiers: HashMap::new(), function_modules: HashMap::new(), + struct_name_locations: HashMap::new(), func_id_to_trait: HashMap::new(), dependency_graph: petgraph::graph::DiGraph::new(), dependency_graph_indices: HashMap::new(), @@ -531,6 +539,7 @@ impl Default for NodeInterner { type_alias_ref: Vec::new(), type_ref_locations: Vec::new(), quoted_types: Default::default(), + track_references: false, location_indices: LocationIndices::default(), reference_graph: petgraph::graph::DiGraph::new(), reference_graph_indices: HashMap::new(), @@ -928,6 +937,14 @@ impl NodeInterner { &self.struct_attributes[struct_id] } + pub fn add_struct_location(&mut self, struct_id: StructId, location: Location) { + self.struct_name_locations.insert(struct_id, location); + } + + pub fn struct_location(&self, struct_id: &StructId) -> Location { + self.struct_name_locations[struct_id] + } + pub fn global_attributes(&self, global_id: &GlobalId) -> &[SecondaryAttribute] { &self.global_attributes[global_id] } diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 92924e701a6..e9777261405 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -266,6 +266,16 @@ pub(crate) fn resolve_workspace_for_source_path(file_path: &Path) -> Result( + file_manager: &'file_manager FileManager, + parsed_files: &'parsed_files ParsedFiles, + package: &Package, +) -> (Context<'file_manager, 'parsed_files>, CrateId) { + let (mut context, crate_id) = nargo::prepare_package(file_manager, parsed_files, package); + context.track_references(); + (context, crate_id) +} + /// Prepares a package from a source string /// This is useful for situations when we don't need dependencies /// and just need to operate on single file. @@ -283,6 +293,8 @@ fn prepare_source(source: String, state: &mut LspState) -> (Context<'static, 'st let parsed_files = parse_diff(&file_manager, state); let mut context = Context::new(file_manager, parsed_files); + context.track_references(); + let root_crate_id = prepare_crate(&mut context, file_name); (context, root_crate_id) diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index 3856bdc79e9..da3b95ce8e0 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -1,7 +1,7 @@ use std::ops::ControlFlow; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; -use nargo::{insert_all_files_for_workspace_into_file_manager, prepare_package}; +use nargo::insert_all_files_for_workspace_into_file_manager; use noirc_driver::{check_crate, file_manager_with_stdlib}; use noirc_errors::{DiagnosticKind, FileDiagnostic}; @@ -137,7 +137,7 @@ fn process_noir_document( .into_iter() .flat_map(|package| -> Vec { let (mut context, crate_id) = - prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); let file_diagnostics = match check_crate(&mut context, crate_id, false, false, false) { Ok(((), warnings)) => warnings, diff --git a/tooling/lsp/src/requests/goto_declaration.rs b/tooling/lsp/src/requests/goto_declaration.rs index 4ffe6abf88a..730b87493b0 100644 --- a/tooling/lsp/src/requests/goto_declaration.rs +++ b/tooling/lsp/src/requests/goto_declaration.rs @@ -38,7 +38,7 @@ fn on_goto_definition_inner( let parsed_files = parse_diff(&workspace_file_manager, state); let (mut context, crate_id) = - nargo::prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); let package_root_path = package.root_dir.as_os_str().to_string_lossy().into_owned(); let interner = if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 4985c565e06..81b1e7d5d8d 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -46,7 +46,7 @@ fn on_goto_definition_inner( let parsed_files = parse_diff(&workspace_file_manager, state); let (mut context, crate_id) = - nargo::prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); let package_root_path = package.root_dir.as_os_str().to_string_lossy().into_owned(); let interner = if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { diff --git a/tooling/lsp/src/requests/rename.rs b/tooling/lsp/src/requests/rename.rs index 9f6416a2c63..e073178598b 100644 --- a/tooling/lsp/src/requests/rename.rs +++ b/tooling/lsp/src/requests/rename.rs @@ -96,7 +96,7 @@ where let parsed_files = parse_diff(&workspace_file_manager, state); let (mut context, crate_id) = - nargo::prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); let interner; if let Some(def_interner) = state.cached_definitions.get(&package_root_path) { @@ -137,28 +137,32 @@ mod rename_tests { use lsp_types::{Position, Range, WorkDoneProgressParams}; use tokio::test; - async fn check_rename_succeeds(directory: &str, name: &str, ranges: &[Range]) { + async fn check_rename_succeeds(directory: &str, name: &str) { let (mut state, noir_text_document) = test_utils::init_lsp_server(directory).await; let main_path = noir_text_document.path(); - // As we process the rename requests we'll check that the request position actually - // includes the target name. + // First we find out all of the occurrences of `name` in the main.nr file. + // Note that this only works if that name doesn't show up in other places where we don't + // expect a rename, but we craft our tests to avoid that. let file_contents = std::fs::read_to_string(main_path) .unwrap_or_else(|_| panic!("Couldn't read file {}", main_path)); - let file_lines: Vec<&str> = file_contents.lines().collect(); + let ranges: Vec<_> = file_lines + .iter() + .enumerate() + .filter_map(|(line_num, line)| { + line.find(name).map(|index| { + let start = Position { line: line_num as u32, character: index as u32 }; + let end = + Position { line: line_num as u32, character: (index + name.len()) as u32 }; + Range { start, end } + }) + }) + .collect(); // Test renaming works on any instance of the symbol. - for target_range in ranges { - assert_eq!(target_range.start.line, target_range.end.line); - - // Check that the range includes the target name - let line = file_lines[target_range.start.line as usize]; - let chunk = - &line[target_range.start.character as usize..target_range.end.character as usize]; - assert_eq!(chunk, name); - + for target_range in &ranges { let target_position = target_range.start; let params = RenameParams { @@ -187,7 +191,7 @@ mod rename_tests { #[test] async fn test_on_prepare_rename_request_cannot_be_applied() { - let (mut state, noir_text_document) = test_utils::init_lsp_server("rename").await; + let (mut state, noir_text_document) = test_utils::init_lsp_server("rename_function").await; let params = TextDocumentPositionParams { text_document: lsp_types::TextDocumentIdentifier { uri: noir_text_document }, @@ -205,45 +209,22 @@ mod rename_tests { } #[test] - async fn test_on_rename_request() { - const ANOTHER_FUNCTION_REFERENCE: Range = Range { - start: Position { line: 9, character: 12 }, - end: Position { line: 9, character: 28 }, - }; - const ANOTHER_FUNCTION_DECLARATION: Range = Range { - start: Position { line: 4, character: 3 }, - end: Position { line: 4, character: 19 }, - }; - // The ranges of positions which represent the usage of the `another_function` symbol. - const ANOTHER_FUNCTION_RANGES: &[Range] = &[ - ANOTHER_FUNCTION_DECLARATION, - ANOTHER_FUNCTION_REFERENCE, - Range { - start: Position { line: 13, character: 12 }, - end: Position { line: 13, character: 28 }, - }, - Range { - start: Position { line: 19, character: 15 }, - end: Position { line: 19, character: 31 }, - }, - ]; + async fn test_rename_function() { + check_rename_succeeds("rename_function", "another_function").await; + } - check_rename_succeeds("rename", "another_function", ANOTHER_FUNCTION_RANGES).await; + #[test] + async fn test_rename_qualified_function() { + check_rename_succeeds("rename_qualified_function", "bar").await; } #[test] - async fn test_on_rename_request_works_with_qualified_path() { - const BAR_FUNCTION_REFERENCE: Range = Range { - start: Position { line: 1, character: 9 }, - end: Position { line: 1, character: 12 }, - }; - const BAR_FUNCTION_DECLARATION: Range = Range { - start: Position { line: 5, character: 11 }, - end: Position { line: 5, character: 14 }, - }; - // The ranges of positions which represent the usage of the `bar` symbol. - const BAR_FUNCTION_RANGES: &[Range] = &[BAR_FUNCTION_REFERENCE, BAR_FUNCTION_DECLARATION]; + async fn test_rename_function_in_use_statement() { + check_rename_succeeds("rename_function_use", "some_function").await; + } - check_rename_succeeds("rename_qualified", "bar", BAR_FUNCTION_RANGES).await; + #[test] + async fn test_rename_struct() { + check_rename_succeeds("rename_struct", "Foo").await; } } diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index 83b05ba06a2..acd4f5800f3 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -4,7 +4,6 @@ use async_lsp::{ErrorCode, ResponseError}; use nargo::{ insert_all_files_for_workspace_into_file_manager, ops::{run_test, TestStatus}, - prepare_package, }; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{ @@ -59,7 +58,7 @@ fn on_test_run_request_inner( match workspace.into_iter().next() { Some(package) => { let (mut context, crate_id) = - prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); if check_crate(&mut context, crate_id, false, false, false).is_err() { let result = NargoTestRunResult { id: params.id.clone(), diff --git a/tooling/lsp/src/requests/tests.rs b/tooling/lsp/src/requests/tests.rs index cdf4ad338c4..a2aa3ebc0bf 100644 --- a/tooling/lsp/src/requests/tests.rs +++ b/tooling/lsp/src/requests/tests.rs @@ -2,7 +2,7 @@ use std::future::{self, Future}; use async_lsp::{ErrorCode, LanguageClient, ResponseError}; use lsp_types::{LogMessageParams, MessageType}; -use nargo::{insert_all_files_for_workspace_into_file_manager, prepare_package}; +use nargo::insert_all_files_for_workspace_into_file_manager; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{check_crate, file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; @@ -58,7 +58,7 @@ fn on_tests_request_inner( .into_iter() .filter_map(|package| { let (mut context, crate_id) = - prepare_package(&workspace_file_manager, &parsed_files, package); + crate::prepare_package(&workspace_file_manager, &parsed_files, package); // We ignore the warnings and errors produced by compilation for producing tests // because we can still get the test functions even if compilation fails let _ = check_crate(&mut context, crate_id, false, false, false); diff --git a/tooling/lsp/test_programs/rename_function/Nargo.toml b/tooling/lsp/test_programs/rename_function/Nargo.toml new file mode 100644 index 00000000000..529fde06128 --- /dev/null +++ b/tooling/lsp/test_programs/rename_function/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename_function" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename_function/src/main.nr b/tooling/lsp/test_programs/rename_function/src/main.nr new file mode 100644 index 00000000000..ad526f10966 --- /dev/null +++ b/tooling/lsp/test_programs/rename_function/src/main.nr @@ -0,0 +1,21 @@ +fn some_function() -> Field { + 1 + 2 +} + +fn another_function() -> Field { + 3 + 4 +} + +fn main() { + let _ = another_function(); + + let _ = 1; + + let _ = another_function(); +} + +mod foo { + fn some_other_function() -> Field { + crate::another_function() + } +} diff --git a/tooling/lsp/test_programs/rename_function_use/Nargo.toml b/tooling/lsp/test_programs/rename_function_use/Nargo.toml new file mode 100644 index 00000000000..e2eb25886bf --- /dev/null +++ b/tooling/lsp/test_programs/rename_function_use/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename_function_use" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename_function_use/src/main.nr b/tooling/lsp/test_programs/rename_function_use/src/main.nr new file mode 100644 index 00000000000..e1b7c98ab0f --- /dev/null +++ b/tooling/lsp/test_programs/rename_function_use/src/main.nr @@ -0,0 +1,12 @@ +mod foo { + pub fn some_function() -> Field { + 1 + 2 + } +} + +use foo::some_function; + +fn main() { + let _ = some_function(); +} + diff --git a/tooling/lsp/test_programs/rename_qualified_function/Nargo.toml b/tooling/lsp/test_programs/rename_qualified_function/Nargo.toml new file mode 100644 index 00000000000..c0aaa3ce658 --- /dev/null +++ b/tooling/lsp/test_programs/rename_qualified_function/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename_qualified_function" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename_qualified_function/src/main.nr b/tooling/lsp/test_programs/rename_qualified_function/src/main.nr new file mode 100644 index 00000000000..f1b77796210 --- /dev/null +++ b/tooling/lsp/test_programs/rename_qualified_function/src/main.nr @@ -0,0 +1,9 @@ +fn main() -> pub Field { + foo::bar() +} + +mod foo { + pub fn bar() -> Field { + 1 + } +} diff --git a/tooling/lsp/test_programs/rename_struct/Nargo.toml b/tooling/lsp/test_programs/rename_struct/Nargo.toml new file mode 100644 index 00000000000..e5822098e58 --- /dev/null +++ b/tooling/lsp/test_programs/rename_struct/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename_struct" +type = "bin" +authors = [""] + +[dependencies] diff --git a/tooling/lsp/test_programs/rename_struct/src/main.nr b/tooling/lsp/test_programs/rename_struct/src/main.nr new file mode 100644 index 00000000000..96cccb4d72a --- /dev/null +++ b/tooling/lsp/test_programs/rename_struct/src/main.nr @@ -0,0 +1,18 @@ +mod foo { + mod bar { + struct Foo { + field: Field, + } + } +} + +use foo::bar::Foo; + +fn main(x: Field) -> pub Field { + let foo1 = Foo { field: 1 }; + let foo2 = Foo { field: 2 }; + let Foo { field } = foo1; + x +} + +fn foo(foo: Foo) {}