diff --git a/tooling/lsp/src/requests/code_action/tests.rs b/tooling/lsp/src/requests/code_action/tests.rs index 23026d16d94..35d19324020 100644 --- a/tooling/lsp/src/requests/code_action/tests.rs +++ b/tooling/lsp/src/requests/code_action/tests.rs @@ -1,6 +1,9 @@ #![cfg(test)] -use crate::{notifications::on_did_open_text_document, test_utils, tests::apply_text_edits}; +use crate::{ + notifications::on_did_open_text_document, test_utils, tests::apply_text_edits, + utils::get_cursor_line_and_column, +}; use lsp_types::{ CodeActionContext, CodeActionOrCommand, CodeActionParams, CodeActionResponse, @@ -10,16 +13,12 @@ use lsp_types::{ use super::on_code_action_request; -async fn get_code_action(src: &str) -> CodeActionResponse { +/// Given a string with ">|<" (cursor) in it, returns all code actions that are available +/// at that position together with the string with ">|<" removed. +async fn get_code_action(src: &str) -> (CodeActionResponse, String) { let (mut state, noir_text_document) = test_utils::init_lsp_server("document_symbol").await; - let (line, column) = src - .lines() - .enumerate() - .find_map(|(line_index, line)| line.find(">|<").map(|char_index| (line_index, char_index))) - .expect("Expected to find one >|< in the source code"); - - let src = src.replace(">|<", ""); + let (line, column, src) = get_cursor_line_and_column(src); on_did_open_text_document( &mut state, @@ -35,7 +34,7 @@ async fn get_code_action(src: &str) -> CodeActionResponse { let position = Position { line: line as u32, character: column as u32 }; - on_code_action_request( + let response = on_code_action_request( &mut state, CodeActionParams { text_document: TextDocumentIdentifier { uri: noir_text_document }, @@ -47,11 +46,12 @@ async fn get_code_action(src: &str) -> CodeActionResponse { ) .await .expect("Could not execute on_code_action_request") - .expect("Expected to get a CodeActionResponse, got None") + .expect("Expected to get a CodeActionResponse, got None"); + (response, src) } pub(crate) async fn assert_code_action(title: &str, src: &str, expected: &str) { - let actions = get_code_action(src).await; + let (actions, src) = get_code_action(src).await; let action = actions .iter() .filter_map(|action| { diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index 98bb2aae6e6..64c91dd673d 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -16,6 +16,7 @@ mod completion_tests { }, test_utils, tests::apply_text_edits, + utils::get_cursor_line_and_column, }; use lsp_types::{ @@ -26,19 +27,12 @@ mod completion_tests { }; use tokio::test; - async fn get_completions(src: &str) -> Vec { + /// Given a string with ">|<" (cursor) in it, returns all completions that are available + /// at that position together with the string with ">|<" removed. + async fn get_completions(src: &str) -> (Vec, String) { let (mut state, noir_text_document) = test_utils::init_lsp_server("document_symbol").await; - let (line, column) = src - .lines() - .enumerate() - .filter_map(|(line_index, line)| { - line.find(">|<").map(|char_index| (line_index, char_index)) - }) - .next() - .expect("Expected to find one >|< in the source code"); - - let src = src.replace(">|<", ""); + let (line, column, src) = get_cursor_line_and_column(src); on_did_open_text_document( &mut state, @@ -67,7 +61,9 @@ mod completion_tests { .await .expect("Could not execute on_completion_request"); - if let Some(CompletionResponse::Array(items)) = response { items } else { vec![] } + let items = + if let Some(CompletionResponse::Array(items)) = response { items } else { vec![] }; + (items, src) } fn assert_items_match(mut items: Vec, mut expected: Vec) { @@ -90,12 +86,12 @@ mod completion_tests { } async fn assert_completion(src: &str, expected: Vec) { - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_items_match(items, expected); } async fn assert_completion_excluding_auto_import(src: &str, expected: Vec) { - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; let items = items.into_iter().filter(|item| item.additional_text_edits.is_none()).collect(); assert_items_match(items, expected); } @@ -760,7 +756,7 @@ mod completion_tests { fn foo(x: i>|<) {} "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; let items = items.into_iter().filter(|item| item.label.starts_with('i')).collect(); assert_items_match( @@ -782,7 +778,7 @@ mod completion_tests { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert!(items.iter().any(|item| item.label == "i8")); } @@ -794,7 +790,7 @@ mod completion_tests { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert!( items .iter() @@ -1341,7 +1337,7 @@ mod completion_tests { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; let items = items.into_iter().filter(|item| item.kind == Some(CompletionItemKind::FIELD)); let items = items.collect(); @@ -1431,7 +1427,7 @@ fn main() { } "#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -1444,8 +1440,7 @@ fn main() { }) ); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1477,7 +1472,7 @@ mod foo { } } "#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -1490,8 +1485,7 @@ mod foo { }) ); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -1522,7 +1516,7 @@ mod foo { } } }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -1535,8 +1529,7 @@ mod foo { }) ); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -1574,13 +1567,12 @@ use foo::bar::hello_world; fn main() { hel }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -1622,13 +1614,12 @@ mod other { hel } }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -1648,7 +1639,7 @@ mod other { hel>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert!(items.is_empty()); } @@ -1667,7 +1658,7 @@ mod other { hel>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert!(items.is_empty()); } @@ -1684,7 +1675,7 @@ mod other { hel>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert!(items.is_empty()); } @@ -1703,7 +1694,7 @@ mod other { hello_w>|< } "#; - let mut items = get_completions(src).await; + let (mut items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -1737,7 +1728,7 @@ mod foo { } }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -1751,8 +1742,7 @@ mod foo { }) ); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -1784,12 +1774,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1822,12 +1811,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1862,12 +1850,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1908,12 +1895,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1946,12 +1932,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -1986,12 +1971,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -2022,12 +2006,11 @@ fn main() { two_hello_ }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); assert_eq!(item.sort_text, Some(auto_import_sort_text())); } @@ -2097,7 +2080,7 @@ fn main() { } } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -2118,7 +2101,7 @@ fn main() { zeroe>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -2264,7 +2247,7 @@ fn main() { x.>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; if items.iter().any(|item| item.label == "__assert_max_bit_size") { panic!("Private method __assert_max_bit_size was suggested"); } @@ -2304,7 +2287,7 @@ fn main() { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -2331,7 +2314,7 @@ fn main() { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -2356,7 +2339,7 @@ fn main() { fn main() {} "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -2684,9 +2667,9 @@ fn main() { } "#; - let completions = get_completions(src).await; - assert_eq!(completions.len(), 1); - assert_eq!(completions[0].label, "unquote!(…)"); + let (items, _) = get_completions(src).await; + assert_eq!(items.len(), 1); + assert_eq!(items[0].label, "unquote!(…)"); } #[test] @@ -2855,7 +2838,7 @@ fn main() { foo.b>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); assert!(items[0].label == "bar_baz()"); } @@ -2874,7 +2857,7 @@ fn main() { x.fo>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); } @@ -2925,7 +2908,7 @@ fn main() { } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 2); } @@ -2946,14 +2929,13 @@ fn main() { Field::fooba>|< } "#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); assert_eq!(item.label_details.unwrap().detail, Some("(use moo::Foo)".to_string())); - let new_code = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let new_code = apply_text_edits(&src, &item.additional_text_edits.unwrap()); let expected = r#"use moo::Foo; @@ -2992,14 +2974,13 @@ fn main() { x.fooba>|< } "#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); assert_eq!(item.label_details.unwrap().detail, Some("(use moo::Foo)".to_string())); - let new_code = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let new_code = apply_text_edits(&src, &item.additional_text_edits.unwrap()); let expected = r#"use moo::Foo; @@ -3043,14 +3024,13 @@ fn main() { x.fooba>|< } "#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); assert_eq!(item.label_details.unwrap().detail, Some("(use moo::Bar)".to_string())); - let new_code = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let new_code = apply_text_edits(&src, &item.additional_text_edits.unwrap()); let expected = r#"use moo::Bar; @@ -3088,7 +3068,7 @@ fn main() { Enum::Var>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -3120,7 +3100,7 @@ fn main() { Enum::Var>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -3149,7 +3129,7 @@ fn main() { ThisIsA>|< } "#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 1); let item = &items[0]; @@ -3172,7 +3152,7 @@ fn main() { SomeStru>|< }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -3200,8 +3180,7 @@ fn main() { SomeStru }"#; - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -3221,7 +3200,7 @@ fn main() { SomeStru>|< }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -3249,8 +3228,7 @@ fn main() { SomeStru }"#; - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -3272,7 +3250,7 @@ fn main() { SomeStru>|< }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -3302,8 +3280,7 @@ fn main() { SomeStru }"#; - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } @@ -3325,7 +3302,7 @@ fn main() { SomeStru>|< }"#; - let items = get_completions(src).await; + let (items, _) = get_completions(src).await; assert_eq!(items.len(), 0); } @@ -3349,7 +3326,7 @@ fn main() { SomeStru>|< }"#; - let mut items = get_completions(src).await; + let (mut items, src) = get_completions(src).await; assert_eq!(items.len(), 1); let item = items.remove(0); @@ -3381,8 +3358,7 @@ fn main() { SomeStru }"#; - let changed = - apply_text_edits(&src.replace(">|<", ""), &item.additional_text_edits.unwrap()); + let changed = apply_text_edits(&src, &item.additional_text_edits.unwrap()); assert_eq!(changed, expected); } } diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index 9126ab38e10..a5ffd1155fa 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -19,6 +19,7 @@ use nargo_fmt::Config; use noirc_frontend::ast::Ident; use noirc_frontend::graph::CrateId; use noirc_frontend::hir::def_map::{CrateDefMap, ModuleId}; +use noirc_frontend::node_interner::ReferenceId; use noirc_frontend::parser::ParserError; use noirc_frontend::usage_tracker::UsageTracker; use noirc_frontend::{graph::Dependency, node_interner::NodeInterner}; @@ -590,68 +591,104 @@ pub(crate) fn find_all_references_in_workspace( include_self_type_name: bool, ) -> Option> { // First find the node that's referenced by the given location, if any - let referenced = interner.find_referenced(location); + let referenced = interner.find_referenced(location)?; + let name = get_reference_name(referenced, interner)?; - if let Some(referenced) = referenced { - // If we found the referenced node, find its location - let referenced_location = interner.reference_location(referenced); + // If we found the referenced node, find its location + let referenced_location = interner.reference_location(referenced); - // Now we find all references that point to this location, in all interners - // (there's one interner per package, and all interners in a workspace rely on the - // same FileManager so a Location/FileId in one package is the same as in another package) - let mut locations = find_all_references( + // Now we find all references that point to this location, in all interners + // (there's one interner per package, and all interners in a workspace rely on the + // same FileManager so a Location/FileId in one package is the same as in another package) + let mut locations = find_all_references( + referenced_location, + interner, + include_declaration, + include_self_type_name, + ); + for cache_data in package_cache.values() { + locations.extend(find_all_references( referenced_location, - interner, - files, + &cache_data.node_interner, include_declaration, include_self_type_name, - ); - for cache_data in package_cache.values() { - locations.extend(find_all_references( - referenced_location, - &cache_data.node_interner, - files, - include_declaration, - include_self_type_name, - )); - } - - // The LSP client usually removes duplicate locations, but we do it here just in case they don't - locations.sort_by_key(|location| { - ( - location.uri.to_string(), - location.range.start.line, - location.range.start.character, - location.range.end.line, - location.range.end.character, - ) - }); - locations.dedup(); - - if locations.is_empty() { None } else { Some(locations) } - } else { - None + )); } + + // Only keep locations whose span, when read from the file, matches "name" + // (it might not match because of macro expansions) + locations.retain(|location| { + let Some(file) = files.get_file(location.file) else { + return false; + }; + + let Some(substring) = + file.source().get(location.span.start() as usize..location.span.end() as usize) + else { + return false; + }; + + substring == name + }); + + let mut locations = locations + .iter() + .filter_map(|location| to_lsp_location(files, location.file, location.span)) + .collect::>(); + + // The LSP client usually removes duplicate locations, but we do it here just in case they don't + locations.sort_by_key(|location| { + ( + location.uri.to_string(), + location.range.start.line, + location.range.start.character, + location.range.end.line, + location.range.end.character, + ) + }); + locations.dedup(); + + if locations.is_empty() { None } else { Some(locations) } } pub(crate) fn find_all_references( referenced_location: noirc_errors::Location, interner: &NodeInterner, - files: &FileMap, include_declaration: bool, include_self_type_name: bool, -) -> Vec { +) -> Vec { interner .find_all_references(referenced_location, include_declaration, include_self_type_name) - .map(|locations| { - locations - .iter() - .filter_map(|location| to_lsp_location(files, location.file, location.span)) - .collect() - }) .unwrap_or_default() } +fn get_reference_name(reference: ReferenceId, interner: &NodeInterner) -> Option { + match reference { + ReferenceId::Module(module_id) => { + Some(interner.try_module_attributes(&module_id)?.name.clone()) + } + ReferenceId::Type(type_id) => Some(interner.get_type(type_id).borrow().name.to_string()), + ReferenceId::StructMember(type_id, index) => { + Some(interner.get_type(type_id).borrow().field_at(index).name.to_string()) + } + ReferenceId::EnumVariant(type_id, index) => { + Some(interner.get_type(type_id).borrow().variant_at(index).name.to_string()) + } + ReferenceId::Trait(trait_id) => Some(interner.get_trait(trait_id).name.to_string()), + ReferenceId::Global(global_id) => Some(interner.get_global(global_id).ident.to_string()), + ReferenceId::Function(func_id) => Some(interner.function_name(&func_id).to_string()), + ReferenceId::Alias(type_alias_id) => { + Some(interner.get_type_alias(type_alias_id).borrow().name.to_string()) + } + ReferenceId::Local(definition_id) => { + Some(interner.definition_name(definition_id).to_string()) + } + ReferenceId::Reference(location, _) => { + get_reference_name(interner.find_referenced(location)?, interner) + } + } +} + /// Represents a trait reexported from a given module with a name. pub(crate) struct TraitReexport { pub(super) module_id: ModuleId, diff --git a/tooling/lsp/src/requests/references.rs b/tooling/lsp/src/requests/references.rs index fbe69c99871..73188b18ada 100644 --- a/tooling/lsp/src/requests/references.rs +++ b/tooling/lsp/src/requests/references.rs @@ -28,10 +28,12 @@ pub(crate) fn on_references_request( #[cfg(test)] mod references_tests { use super::*; - use crate::notifications; use crate::test_utils::{self, search_in_file}; + use crate::utils::get_cursor_line_and_column; + use crate::{notifications, on_did_open_text_document}; use lsp_types::{ - PartialResultParams, Position, Range, ReferenceContext, TextDocumentPositionParams, Url, + DidOpenTextDocumentParams, PartialResultParams, Position, Range, ReferenceContext, + TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, Url, WorkDoneProgressParams, }; use tokio::test; @@ -55,9 +57,7 @@ mod references_tests { let params = ReferenceParams { text_document_position: TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { - uri: noir_text_document.clone(), - }, + text_document: TextDocumentIdentifier { uri: noir_text_document.clone() }, position: target_position, }, work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, @@ -123,7 +123,7 @@ mod references_tests { let params = ReferenceParams { text_document_position: TextDocumentPositionParams { - text_document: lsp_types::TextDocumentIdentifier { uri: one_lib.clone() }, + text_document: TextDocumentIdentifier { uri: one_lib.clone() }, position: Position { line: 0, character: 7 }, }, work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, @@ -170,4 +170,56 @@ mod references_tests { } ); } + + #[test] + async fn ignores_macro_expansions() { + let src = " + #[foo] + struct Fo>| Quoted { + let t = s.as_type(); + quote { + impl Trait for $t {} + } + } + "; + + let (mut state, noir_text_document) = test_utils::init_lsp_server("document_symbol").await; + + let (line, column, src) = get_cursor_line_and_column(src); + + on_did_open_text_document( + &mut state, + DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: noir_text_document.clone(), + language_id: "noir".to_string(), + version: 0, + text: src.to_string(), + }, + }, + ); + + let result = on_references_request( + &mut state, + ReferenceParams { + text_document_position: TextDocumentPositionParams { + text_document: TextDocumentIdentifier { uri: noir_text_document }, + position: Position { line: line as u32, character: column as u32 }, + }, + work_done_progress_params: WorkDoneProgressParams { work_done_token: None }, + partial_result_params: PartialResultParams { partial_result_token: None }, + context: ReferenceContext { include_declaration: true }, + }, + ) + .await; + let locations = result.unwrap().unwrap(); + assert_eq!(locations.len(), 1); + assert_eq!(locations[0].range.start.line, 2); // Just the one for "struct Foo" + } } diff --git a/tooling/lsp/src/requests/signature_help/tests.rs b/tooling/lsp/src/requests/signature_help/tests.rs index a5cf7c32e1e..b102a3f03b1 100644 --- a/tooling/lsp/src/requests/signature_help/tests.rs +++ b/tooling/lsp/src/requests/signature_help/tests.rs @@ -2,6 +2,7 @@ mod signature_help_tests { use crate::{ notifications::on_did_open_text_document, requests::on_signature_help_request, test_utils, + utils::get_cursor_line_and_column, }; use lsp_types::{ @@ -14,15 +15,7 @@ mod signature_help_tests { async fn get_signature_help(src: &str) -> SignatureHelp { let (mut state, noir_text_document) = test_utils::init_lsp_server("document_symbol").await; - let (line, column) = src - .lines() - .enumerate() - .find_map(|(line_index, line)| { - line.find(">|<").map(|char_index| (line_index, char_index)) - }) - .expect("Expected to find one >|< in the source code"); - - let src = src.replace(">|<", ""); + let (line, column, src) = get_cursor_line_and_column(src); on_did_open_text_document( &mut state, diff --git a/tooling/lsp/src/utils.rs b/tooling/lsp/src/utils.rs index ca607128bf2..5fe5d14bc6d 100644 --- a/tooling/lsp/src/utils.rs +++ b/tooling/lsp/src/utils.rs @@ -53,3 +53,19 @@ pub(crate) fn character_to_line_offset(line: &str, character: u32) -> Option|<" (cursor) in it, returns: +/// 1. The line where the cursor is (zero-based) +/// 2. The column where the cursor is (zero-based) +/// 3. that string with ">|<" removed +#[cfg(test)] +pub(crate) fn get_cursor_line_and_column(src: &str) -> (usize, usize, String) { + let (line, column) = src + .lines() + .enumerate() + .find_map(|(line_index, line)| line.find(">|<").map(|char_index| (line_index, char_index))) + .expect("Expected to find one >|< in the source code"); + + let src = src.replace(">|<", ""); + (line, column, src) +}