diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index 88c6509f05a..36674ef2478 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -9,6 +9,7 @@ use crate::ast::UnresolvedGenerics; use crate::debug::DebugInstrumenter; use crate::elaborator::UnstableFeature; use crate::graph::{CrateGraph, CrateId}; +use crate::hir::def_map::DefMaps; use crate::hir_def::function::FuncMeta; use crate::node_interner::{FuncId, NodeInterner, TypeId}; use crate::parser::ParserError; @@ -141,17 +142,7 @@ impl Context<'_, '_> { } pub fn fully_qualified_function_name(&self, crate_id: &CrateId, id: &FuncId) -> String { - let def_map = self.def_map(crate_id).expect("The local crate should be analyzed already"); - - let name = self.def_interner.function_name(id); - - let module_id = self.def_interner.function_module(*id); - let module = self.module(module_id); - - let parent = - def_map.get_module_path_with_separator(module_id.local_id, module.parent, "::"); - - if parent.is_empty() { name.into() } else { format!("{parent}::{name}") } + fully_qualified_function_name(*crate_id, *id, &self.def_interner, &self.def_maps) } /// Returns a fully-qualified path to the given [TypeId] from the given [CrateId]. This function also @@ -185,27 +176,12 @@ impl Context<'_, '_> { crate_id: &CrateId, pattern: &FunctionNameMatch, ) -> Vec<(String, TestFunction)> { - let interner = &self.def_interner; - let def_map = self.def_map(crate_id).expect("The local crate should be analyzed already"); - - def_map - .get_all_test_functions(interner) - .filter_map(|test_function| { - let fully_qualified_name = - self.fully_qualified_function_name(crate_id, &test_function.id); - match &pattern { - FunctionNameMatch::Anything => Some((fully_qualified_name, test_function)), - FunctionNameMatch::Exact(patterns) => patterns - .iter() - .any(|pattern| &fully_qualified_name == pattern) - .then_some((fully_qualified_name, test_function)), - FunctionNameMatch::Contains(patterns) => patterns - .iter() - .any(|pattern| fully_qualified_name.contains(pattern)) - .then_some((fully_qualified_name, test_function)), - } - }) - .collect() + get_all_test_functions_in_crate_matching( + *crate_id, + pattern, + &self.def_interner, + &self.def_maps, + ) } /// Returns a list of all functions in the current crate marked with `#[fuzz]` @@ -303,3 +279,49 @@ impl Context<'_, '_> { self.interpreter_output = Some(output); } } + +pub fn get_all_test_functions_in_crate_matching( + crate_id: CrateId, + pattern: &FunctionNameMatch, + interner: &NodeInterner, + def_maps: &DefMaps, +) -> Vec<(String, TestFunction)> { + let def_map = def_maps.get(&crate_id).expect("The local crate should be analyzed already"); + + def_map + .get_all_test_functions(interner) + .filter_map(|test_function| { + let fully_qualified_name = + fully_qualified_function_name(crate_id, test_function.id, interner, def_maps); + match &pattern { + FunctionNameMatch::Anything => Some((fully_qualified_name, test_function)), + FunctionNameMatch::Exact(patterns) => patterns + .iter() + .any(|pattern| &fully_qualified_name == pattern) + .then_some((fully_qualified_name, test_function)), + FunctionNameMatch::Contains(patterns) => patterns + .iter() + .any(|pattern| fully_qualified_name.contains(pattern)) + .then_some((fully_qualified_name, test_function)), + } + }) + .collect() +} + +fn fully_qualified_function_name( + crate_id: CrateId, + id: FuncId, + interner: &NodeInterner, + def_maps: &DefMaps, +) -> String { + let def_map = def_maps.get(&crate_id).expect("The local crate should be analyzed already"); + + let name = interner.function_name(&id); + + let module_id = interner.function_module(id); + let module = module_id.module(def_maps); + + let parent = def_map.get_module_path_with_separator(module_id.local_id, module.parent, "::"); + + if parent.is_empty() { name.into() } else { format!("{parent}::{name}") } +} diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index 65a761a8264..df605008865 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -12,7 +12,9 @@ use crate::usage_tracker::UsageTracker; use std::collections::BTreeMap; use crate::ast::{Ident, ItemVisibility, Path, PathKind, PathSegment}; -use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleData, ModuleDefId, ModuleId, PerNs}; +use crate::hir::def_map::{ + CrateDefMap, DefMaps, LocalModuleId, ModuleData, ModuleDefId, ModuleId, PerNs, +}; use super::errors::ResolverError; use super::visibility::item_in_module_is_visible; @@ -161,7 +163,7 @@ impl<'a> From<&'a PathResolutionError> for CustomDiagnostic { pub fn resolve_import( path: Path, importing_module: ModuleId, - def_maps: &BTreeMap, + def_maps: &DefMaps, usage_tracker: &mut UsageTracker, references_tracker: Option, ) -> ImportResolutionResult { @@ -194,7 +196,7 @@ fn path_segment_to_typed_path_segment(segment: PathSegment) -> TypedPathSegment pub fn resolve_path_kind<'r>( path: TypedPath, importing_module: ModuleId, - def_maps: &BTreeMap, + def_maps: &DefMaps, references_tracker: Option>, ) -> Result<(TypedPath, ModuleId, Option>), PathResolutionError> { let mut solver = @@ -424,7 +426,7 @@ impl<'def_maps, 'usage_tracker, 'references_tracker> } } -fn get_module(def_maps: &BTreeMap, module: ModuleId) -> &ModuleData { +fn get_module(def_maps: &DefMaps, module: ModuleId) -> &ModuleData { let message = "A crate should always be present for a given crate id"; &def_maps.get(&module.krate).expect(message)[module.local_id] } diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs index b2c816a1f18..0c88414021c 100644 --- a/compiler/noirc_frontend/src/hir/resolution/visibility.rs +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -1,9 +1,6 @@ use crate::Type; -use crate::graph::CrateId; use crate::node_interner::{FuncId, NodeInterner, TraitId, TypeId}; -use std::collections::BTreeMap; - use crate::ast::ItemVisibility; use crate::hir::def_map::{CrateDefMap, DefMaps, LocalModuleId, ModuleId}; @@ -17,7 +14,7 @@ use crate::hir::def_map::{CrateDefMap, DefMaps, LocalModuleId, ModuleId}; /// } /// ``` pub fn item_in_module_is_visible( - def_maps: &BTreeMap, + def_maps: &DefMaps, current_module: ModuleId, target_module: ModuleId, visibility: ItemVisibility, @@ -78,7 +75,7 @@ pub fn struct_member_is_visible( struct_id: TypeId, visibility: ItemVisibility, current_module_id: ModuleId, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> bool { type_member_is_visible(struct_id.module_id(), visibility, current_module_id, def_maps) } @@ -87,7 +84,7 @@ pub fn trait_member_is_visible( trait_id: TraitId, visibility: ItemVisibility, current_module_id: ModuleId, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> bool { type_member_is_visible(trait_id.0, visibility, current_module_id, def_maps) } @@ -96,7 +93,7 @@ fn type_member_is_visible( type_module_id: ModuleId, visibility: ItemVisibility, current_module_id: ModuleId, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> bool { match visibility { ItemVisibility::Public => true, diff --git a/compiler/noirc_frontend/src/modules.rs b/compiler/noirc_frontend/src/modules.rs index a74418ef6cd..21548aa9418 100644 --- a/compiler/noirc_frontend/src/modules.rs +++ b/compiler/noirc_frontend/src/modules.rs @@ -1,10 +1,8 @@ -use std::collections::BTreeMap; - use crate::{ ast::{Ident, ItemVisibility}, graph::{CrateId, Dependency}, hir::{ - def_map::{CrateDefMap, ModuleDefId, ModuleId}, + def_map::{DefMaps, ModuleDefId, ModuleId}, resolution::visibility::item_in_module_is_visible, }, node_interner::{NodeInterner, Reexport, ReferenceId}, @@ -14,7 +12,7 @@ use crate::{ pub fn get_parent_module( module_def_id: ModuleDefId, interner: &NodeInterner, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> Option { match module_def_id { ModuleDefId::ModuleId(id) => id.parent(def_maps), @@ -56,7 +54,7 @@ pub fn relative_module_full_path( current_module_id: ModuleId, current_module_parent_id: Option, interner: &NodeInterner, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> Option { let full_path; if let ModuleDefId::ModuleId(module_id) = module_def_id { @@ -208,7 +206,7 @@ pub fn module_def_id_relative_path( defining_module: Option, intermediate_name: &Option, interner: &NodeInterner, - def_maps: &BTreeMap, + def_maps: &DefMaps, ) -> Option { let module_path = if let Some(defining_module) = defining_module { relative_module_id_path( @@ -251,7 +249,7 @@ pub fn module_def_id_is_visible( mut visibility: ItemVisibility, mut defining_module: Option, interner: &NodeInterner, - def_maps: &BTreeMap, + def_maps: &DefMaps, dependencies: &[Dependency], ) -> bool { // First find out which module we need to check. @@ -299,7 +297,7 @@ pub fn get_ancestor_module_reexport( visibility: ItemVisibility, current_module_id: ModuleId, interner: &NodeInterner, - def_maps: &BTreeMap, + def_maps: &DefMaps, dependencies: &[Dependency], ) -> Option { let parent_module = get_parent_module(module_def_id, interner, def_maps)?; diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 138d8271404..522a9d3d175 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -12,12 +12,9 @@ use std::{ }; use acvm::{BlackBoxFunctionSolver, FieldElement}; -use async_lsp::lsp_types::{ - CodeLens, - request::{ - CodeActionRequest, Completion, DocumentSymbolRequest, HoverRequest, InlayHintRequest, - PrepareRenameRequest, References, Rename, SignatureHelpRequest, WorkspaceSymbolRequest, - }, +use async_lsp::lsp_types::request::{ + CodeActionRequest, Completion, DocumentSymbolRequest, HoverRequest, InlayHintRequest, + PrepareRenameRequest, References, Rename, SignatureHelpRequest, WorkspaceSymbolRequest, }; use async_lsp::{ AnyEvent, AnyNotification, AnyRequest, ClientSocket, Error, LspService, ResponseError, @@ -31,7 +28,7 @@ use nargo::{ workspace::Workspace, }; use nargo_toml::{PackageSelection, find_file_manifest, resolve_workspace_from_toml}; -use noirc_driver::{NOIR_ARTIFACT_VERSION_STRING, file_manager_with_stdlib, prepare_crate}; +use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use noirc_frontend::{ ParsedModule, graph::{CrateGraph, CrateId, CrateName}, @@ -95,7 +92,6 @@ pub struct LspState { solver: WrapperSolver, open_documents_count: usize, input_files: HashMap, - cached_lenses: HashMap>, cached_parsed_files: HashMap))>, workspace_cache: HashMap, package_cache: HashMap, @@ -128,7 +124,6 @@ impl LspState { root_path: None, solver: WrapperSolver(Box::new(solver)), input_files: HashMap::new(), - cached_lenses: HashMap::new(), cached_parsed_files: HashMap::new(), workspace_cache: HashMap::new(), package_cache: HashMap::new(), @@ -345,30 +340,6 @@ pub(crate) fn prepare_package<'file_manager, 'parsed_files>( (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. -/// -/// Use case for this is the LSP server and code lenses -/// which operate on single file and need to understand this file -/// in order to offer code lenses to the user -fn prepare_source(source: String, state: &mut LspState) -> (Context<'static, 'static>, CrateId) { - let root = Path::new(""); - let file_name = Path::new("main.nr"); - let mut file_manager = file_manager_with_stdlib(root); - file_manager.add_file_with_source(file_name, source).expect( - "Adding source buffer to file manager should never fail when file manager is empty", - ); - let parsed_files = parse_diff(&file_manager, state); - - let mut context = Context::new(file_manager, parsed_files); - context.activate_lsp_mode(); - - let root_crate_id = prepare_crate(&mut context, file_name); - - (context, root_crate_id) -} - fn parse_diff(file_manager: &FileManager, state: &mut LspState) -> ParsedFiles { if state.options.enable_parsing_cache { let noir_file_hashes: Vec<_> = file_manager @@ -452,22 +423,3 @@ pub fn source_code_overrides(input_files: &HashMap) -> HashMap

ControlFlow> { state.input_files.remove(¶ms.text_document.uri.to_string()); - state.cached_lenses.remove(¶ms.text_document.uri.to_string()); state.workspace_symbol_cache.reprocess_uri(¶ms.text_document.uri); state.open_documents_count -= 1; @@ -154,14 +153,6 @@ pub(crate) fn process_workspace_for_noir_document( }); } - let collected_lenses = crate::requests::collect_lenses_for_package( - &context, - crate_id, - &workspace, - package, - Some(&file_path), - ); - state.cached_lenses.insert(document_uri.to_string(), collected_lenses); state.package_cache.insert( package.root_dir.clone(), PackageCacheData { diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index 77e75999728..ad7487f0a8d 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -1,13 +1,25 @@ use std::future::{self, Future}; -use async_lsp::{ErrorCode, ResponseError}; +use async_lsp::{ + ResponseError, + lsp_types::{Position, TextDocumentPositionParams}, +}; +use fm::{FileId, FileMap, PathString}; use nargo::{package::Package, workspace::Workspace}; -use noirc_driver::check_crate; -use noirc_frontend::hir::{FunctionNameMatch, def_map::ModuleId}; +use noirc_driver::CrateId; +use noirc_frontend::{ + hir::{ + FunctionNameMatch, + def_map::{DefMaps, ModuleId}, + get_all_test_functions_in_crate_matching, + }, + node_interner::NodeInterner, +}; use crate::{ - LspState, byte_span_to_range, prepare_source, resolve_workspace_for_source_path, + LspState, byte_span_to_range, + requests::process_request, types::{CodeLens, CodeLensParams, CodeLensResult, Command}, }; @@ -50,192 +62,182 @@ fn on_code_lens_request_inner( state: &mut LspState, params: CodeLensParams, ) -> Result { - let file_path = params.text_document.uri.to_file_path().map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "URI is not a valid file path") - })?; - - if let Some(collected_lenses) = state.cached_lenses.get(¶ms.text_document.uri.to_string()) { - return Ok(Some(collected_lenses.clone())); - } - - let source_string = std::fs::read_to_string(&file_path).map_err(|_| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not read file from disk") - })?; - - let workspace = resolve_workspace_for_source_path(file_path.as_path()).unwrap(); - - let package = crate::workspace_package_for_file(&workspace, &file_path).ok_or_else(|| { - ResponseError::new(ErrorCode::REQUEST_FAILED, "Could not find package for file") - })?; - - let (mut context, crate_id) = prepare_source(source_string, state); - // We ignore the warnings and errors produced by compilation for producing code lenses - // because we can still get the test functions even if compilation fails - let _ = check_crate(&mut context, crate_id, &Default::default()); - - let collected_lenses = - collect_lenses_for_package(&context, crate_id, &workspace, package, None); - - if collected_lenses.is_empty() { - state.cached_lenses.remove(¶ms.text_document.uri.to_string()); - Ok(None) - } else { - state - .cached_lenses - .insert(params.text_document.uri.to_string().clone(), collected_lenses.clone()); - Ok(Some(collected_lenses)) - } + let Ok(file_path) = params.text_document.uri.to_file_path() else { + return Ok(None); + }; + + let text_document_position_params = TextDocumentPositionParams { + text_document: params.text_document, + position: Position::new(0, 0), + }; + process_request(state, text_document_position_params, |args| { + let file_id = args.files.get_file_id(&PathString::from_path(file_path))?; + let collected_lenses = collect_lenses_for_file( + file_id, + args.workspace, + args.package, + args.crate_id, + args.interner, + args.def_maps, + args.files, + ); + if collected_lenses.is_empty() { None } else { Some(collected_lenses) } + }) } -pub(crate) fn collect_lenses_for_package( - context: &noirc_frontend::hir::Context, - crate_id: noirc_frontend::graph::CrateId, +pub(crate) fn collect_lenses_for_file( + current_file: FileId, workspace: &Workspace, package: &Package, - file_path: Option<&std::path::PathBuf>, + crate_id: CrateId, + interner: &NodeInterner, + def_maps: &DefMaps, + files: &FileMap, ) -> Vec { let mut lenses: Vec = vec![]; - let fm = &context.file_manager; - let files = fm.as_file_map(); - let tests = - context.get_all_test_functions_in_crate_matching(&crate_id, &FunctionNameMatch::Anything); + + let tests = get_all_test_functions_in_crate_matching( + crate_id, + &FunctionNameMatch::Anything, + interner, + def_maps, + ); for (func_name, test_function) in tests { - let location = context.function_meta(&test_function.id).name.location; + let location = interner.function_meta(&test_function.id).name.location; let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if let Some(file_path) = file_path { - if fm.path(file_id).expect("file must exist to contain tests") != *file_path { - continue; - } + if file_id != current_file { + continue; } let range = byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); - - let test_command = Command { - title: with_arrow(TEST_CODELENS_TITLE), - command: TEST_COMMAND.into(), - arguments: Some( - [ - package_selection_args(workspace, package), - vec!["--exact".into(), "--show-output".into(), func_name.clone().into()], - ] - .concat(), - ), - }; - - let test_lens = CodeLens { range, command: Some(test_command), data: None }; - - lenses.push(test_lens); - - let debug_test_command = Command { - title: format!("{GEAR} {DEBUG_TEST_CODELENS_TITLE}"), - command: DEBUG_TEST_COMMAND.into(), - arguments: Some( - [ - package_selection_args(workspace, package), - vec!["--exact".into(), func_name.into()], - ] - .concat(), - ), - }; - - let debug_test_lens = CodeLens { range, command: Some(debug_test_command), data: None }; - - lenses.push(debug_test_lens); + lenses.push(test_lens(workspace, package, &func_name, range)); + lenses.push(debug_test_lens(workspace, package, func_name, range)); } if package.is_binary() { - if let Some(main_func_id) = context.get_main_function(&crate_id) { - let location = context.function_meta(&main_func_id).name.location; + if let Some(main_func_id) = def_maps[&crate_id].main_function() { + let location = interner.function_meta(&main_func_id).name.location; let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if let Some(file_path) = file_path { - if fm.path(file_id).expect("file must exist to contain `main` function") - != *file_path - { - return lenses; - } + if file_id == current_file { + let range = + byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); + lenses.push(compile_lens(workspace, package, range)); + lenses.push(info_lens(workspace, package, range)); + lenses.push(execute_lens(workspace, package, range)); + lenses.push(debug_lens(workspace, package, range)); } - - let range = - byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); - - let compile_command = Command { - title: with_arrow(COMPILE_CODELENS_TITLE), - command: COMPILE_COMMAND.into(), - arguments: Some(package_selection_args(workspace, package)), - }; - - let compile_lens = CodeLens { range, command: Some(compile_command), data: None }; - - lenses.push(compile_lens); - - let internal_command_lenses = [ - (INFO_CODELENS_TITLE, INFO_COMMAND), - (EXECUTE_CODELENS_TITLE, EXECUTE_COMMAND), - (DEBUG_CODELENS_TITLE, DEBUG_COMMAND), - ] - .map(|(title, command)| { - let command = Command { - title: title.to_string(), - command: command.into(), - arguments: Some(package_selection_args(workspace, package)), - }; - CodeLens { range, command: Some(command), data: None } - }); - - lenses.append(&mut Vec::from(internal_command_lenses)); } } if package.is_contract() { // Currently not looking to deduplicate this since we don't have a clear decision on if the Contract stuff is staying - let def_map = - context.def_map(&crate_id).expect("The local crate should be analyzed already"); + let def_map = def_maps.get(&crate_id).expect("The local crate should be analyzed already"); for contract in def_map .get_all_contracts() - .map(|(local_id, _)| context.module(ModuleId { krate: crate_id, local_id })) + .map(|(local_id, _)| ModuleId { krate: crate_id, local_id }.module(def_maps)) { let location = contract.location; let file_id = location.file; - - // Ignore diagnostics for any file that wasn't the file we saved - // TODO: In the future, we could create "related" diagnostics for these files - if let Some(file_path) = file_path { - if fm.path(file_id).expect("file must exist to contain a contract") != *file_path { - continue; - } + if file_id != current_file { + continue; } let range = byte_span_to_range(files, file_id, location.span.into()).unwrap_or_default(); + lenses.push(compile_lens(workspace, package, range)); + lenses.push(info_lens(workspace, package, range)); + } + } - let compile_command = Command { - title: with_arrow(COMPILE_CODELENS_TITLE), - command: COMPILE_COMMAND.into(), - arguments: Some(package_selection_args(workspace, package)), - }; + lenses +} - let compile_lens = CodeLens { range, command: Some(compile_command), data: None }; +fn info_lens( + workspace: &Workspace, + package: &Package, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let info_command = Command { + title: INFO_CODELENS_TITLE.to_string(), + command: INFO_COMMAND.into(), + arguments: Some(package_selection_args(workspace, package)), + }; + CodeLens { range, command: Some(info_command), data: None } +} - lenses.push(compile_lens); +fn execute_lens( + workspace: &Workspace, + package: &Package, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let info_command = Command { + title: EXECUTE_CODELENS_TITLE.to_string(), + command: EXECUTE_COMMAND.into(), + arguments: Some(package_selection_args(workspace, package)), + }; + CodeLens { range, command: Some(info_command), data: None } +} - let info_command = Command { - title: INFO_CODELENS_TITLE.to_string(), - command: INFO_COMMAND.into(), - arguments: Some(package_selection_args(workspace, package)), - }; +fn debug_lens( + workspace: &Workspace, + package: &Package, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let info_command = Command { + title: DEBUG_CODELENS_TITLE.to_string(), + command: DEBUG_COMMAND.into(), + arguments: Some(package_selection_args(workspace, package)), + }; + CodeLens { range, command: Some(info_command), data: None } +} - let info_lens = CodeLens { range, command: Some(info_command), data: None }; +fn compile_lens( + workspace: &Workspace, + package: &Package, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let compile_command = Command { + title: with_arrow(COMPILE_CODELENS_TITLE), + command: COMPILE_COMMAND.into(), + arguments: Some(package_selection_args(workspace, package)), + }; + CodeLens { range, command: Some(compile_command), data: None } +} - lenses.push(info_lens); - } - } +fn test_lens( + workspace: &Workspace, + package: &Package, + func_name: &str, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let test_command = Command { + title: with_arrow(TEST_CODELENS_TITLE), + command: TEST_COMMAND.into(), + arguments: Some( + [ + package_selection_args(workspace, package), + vec!["--exact".into(), "--show-output".into(), func_name.into()], + ] + .concat(), + ), + }; + CodeLens { range, command: Some(test_command), data: None } +} - lenses +fn debug_test_lens( + workspace: &Workspace, + package: &Package, + func_name: String, + range: async_lsp::lsp_types::Range, +) -> CodeLens { + let debug_test_command = Command { + title: format!("{GEAR} {DEBUG_TEST_CODELENS_TITLE}"), + command: DEBUG_TEST_COMMAND.into(), + arguments: Some( + [package_selection_args(workspace, package), vec!["--exact".into(), func_name.into()]] + .concat(), + ), + }; + CodeLens { range, command: Some(debug_test_command), data: None } } diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index cdfb0bce88a..2e522912d26 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -15,6 +15,8 @@ use lsp_types::{ TextDocumentSyncCapability, TextDocumentSyncKind, TypeDefinitionProviderCapability, Url, WorkDoneProgressOptions, }; +use nargo::package::Package; +use nargo::workspace::Workspace; use nargo_fmt::Config; use noirc_frontend::ast::Ident; @@ -62,12 +64,11 @@ mod tests; mod workspace_symbol; pub(crate) use { - code_action::on_code_action_request, code_lens_request::collect_lenses_for_package, - code_lens_request::on_code_lens_request, completion::on_completion_request, - document_symbol::on_document_symbol_request, expand::on_expand_request, - goto_declaration::on_goto_declaration_request, goto_definition::on_goto_definition_request, - goto_definition::on_goto_type_definition_request, hover::on_hover_request, - inlay_hint::on_inlay_hint_request, references::on_references_request, + code_action::on_code_action_request, code_lens_request::on_code_lens_request, + completion::on_completion_request, document_symbol::on_document_symbol_request, + expand::on_expand_request, goto_declaration::on_goto_declaration_request, + goto_definition::on_goto_definition_request, goto_definition::on_goto_type_definition_request, + hover::on_hover_request, inlay_hint::on_inlay_hint_request, references::on_references_request, rename::on_prepare_rename_request, rename::on_rename_request, signature_help::on_signature_help_request, test_run::on_test_run_request, tests::on_tests_request, workspace_symbol::on_workspace_symbol_request, @@ -455,6 +456,8 @@ pub(crate) fn on_shutdown( pub(crate) struct ProcessRequestCallbackArgs<'a> { location: noirc_errors::Location, + workspace: &'a Workspace, + package: &'a Package, files: &'a FileMap, interner: &'a NodeInterner, package_cache: &'a HashMap, @@ -519,6 +522,8 @@ where Ok(callback(ProcessRequestCallbackArgs { location, + workspace: &workspace, + package, files, interner, package_cache: &state.package_cache, @@ -584,6 +589,8 @@ where Ok(callback(ProcessRequestCallbackArgs { location, + workspace: &workspace, + package, files, interner, package_cache: &state.package_cache, diff --git a/tooling/nargo_expand/src/lib.rs b/tooling/nargo_expand/src/lib.rs index b77f9c69e9c..21c8c6b4027 100644 --- a/tooling/nargo_expand/src/lib.rs +++ b/tooling/nargo_expand/src/lib.rs @@ -1,10 +1,8 @@ -use std::collections::BTreeMap; - use nargo_fmt::ImportsGranularity; use noirc_driver::CrateId; use noirc_frontend::{ graph::CrateGraph, - hir::def_map::{CrateDefMap, ModuleId}, + hir::def_map::{DefMaps, ModuleId}, node_interner::NodeInterner, parse_program_with_dummy_file, }; @@ -18,7 +16,7 @@ mod printer; pub fn get_expanded_crate( crate_id: CrateId, crate_graph: &CrateGraph, - def_maps: &BTreeMap, + def_maps: &DefMaps, interner: &NodeInterner, ) -> String { let root_module_id = def_maps[&crate_id].root();