diff --git a/compiler/noirc_frontend/src/resolve_locations.rs b/compiler/noirc_frontend/src/resolve_locations.rs index 95ced90698..c6834a4361 100644 --- a/compiler/noirc_frontend/src/resolve_locations.rs +++ b/compiler/noirc_frontend/src/resolve_locations.rs @@ -33,9 +33,13 @@ impl NodeInterner { /// Returns the [Location] of the definition of the given Ident found at [Span] of the given [FileId]. /// Returns [None] when definition is not found. - pub fn get_definition_location_from(&self, location: Location) -> Option { + pub fn get_definition_location_from( + &self, + location: Location, + return_type_location_instead: bool, + ) -> Option { self.find_location_index(location) - .and_then(|index| self.resolve_location(index)) + .and_then(|index| self.resolve_location(index, return_type_location_instead)) .or_else(|| self.try_resolve_trait_impl_location(location)) .or_else(|| self.try_resolve_trait_method_declaration(location)) } @@ -43,7 +47,7 @@ impl NodeInterner { pub fn get_declaration_location_from(&self, location: Location) -> Option { self.try_resolve_trait_method_declaration(location).or_else(|| { self.find_location_index(location) - .and_then(|index| self.resolve_location(index)) + .and_then(|index| self.resolve_location(index, false)) .and_then(|found_impl_location| { self.try_resolve_trait_method_declaration(found_impl_location) }) @@ -53,12 +57,31 @@ impl NodeInterner { /// For a given [Index] we return [Location] to which we resolved to /// We currently return None for features not yet implemented /// TODO(#3659): LSP goto def should error when Ident at Location could not resolve - fn resolve_location(&self, index: impl Into) -> Option { + fn resolve_location( + &self, + index: impl Into, + return_type_location_instead: bool, + ) -> Option { + if return_type_location_instead { + return self.get_type_location_from_index(index); + } + let node = self.nodes.get(index.into())?; match node { - Node::Function(func) => self.resolve_location(func.as_expr()), - Node::Expression(expression) => self.resolve_expression_location(expression), + Node::Function(func) => { + self.resolve_location(func.as_expr(), return_type_location_instead) + } + Node::Expression(expression) => { + self.resolve_expression_location(expression, return_type_location_instead) + } + _ => None, + } + } + + fn get_type_location_from_index(&self, index: impl Into) -> Option { + match self.id_type(index.into()) { + Type::Struct(struct_type, _) => Some(struct_type.borrow().location), _ => None, } } @@ -66,7 +89,11 @@ impl NodeInterner { /// Resolves the [Location] of the definition for a given [HirExpression] /// /// Note: current the code returns None because some expressions are not yet implemented. - fn resolve_expression_location(&self, expression: &HirExpression) -> Option { + fn resolve_expression_location( + &self, + expression: &HirExpression, + return_type_location_instead: bool, + ) -> Option { match expression { HirExpression::Ident(ident) => { let definition_info = self.definition(ident.id); @@ -88,7 +115,7 @@ impl NodeInterner { } HirExpression::Call(expr_call) => { let func = expr_call.func; - self.resolve_location(func) + self.resolve_location(func, return_type_location_instead) } _ => None, diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 1099ad6026..30e42a735f 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -34,7 +34,8 @@ use notifications::{ }; use requests::{ on_code_lens_request, on_formatting, on_goto_declaration_request, on_goto_definition_request, - on_initialize, on_profile_run_request, on_shutdown, on_test_run_request, on_tests_request, + on_goto_type_definition_request, on_initialize, on_profile_run_request, on_shutdown, + on_test_run_request, on_tests_request, }; use serde_json::Value as JsonValue; use thiserror::Error; @@ -98,6 +99,7 @@ impl NargoLspService { .request::(on_profile_run_request) .request::(on_goto_definition_request) .request::(on_goto_declaration_request) + .request::(on_goto_type_definition_request) .notification::(on_initialized) .notification::(on_did_change_configuration) .notification::(on_did_open_text_document) diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index 277bbf013f..c339bad3d9 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -4,6 +4,7 @@ use crate::resolve_workspace_for_source_path; use crate::{types::GotoDefinitionResult, LspState}; use async_lsp::{ErrorCode, ResponseError}; +use lsp_types::request::GotoTypeDefinitionParams; use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse}; use nargo::insert_all_files_for_workspace_into_file_manager; use noirc_driver::file_manager_with_stdlib; @@ -14,13 +15,22 @@ pub(crate) fn on_goto_definition_request( state: &mut LspState, params: GotoDefinitionParams, ) -> impl Future> { - let result = on_goto_definition_inner(state, params); + let result = on_goto_definition_inner(state, params, false); + future::ready(result) +} + +pub(crate) fn on_goto_type_definition_request( + state: &mut LspState, + params: GotoTypeDefinitionParams, +) -> impl Future> { + let result = on_goto_definition_inner(state, params, true); future::ready(result) } fn on_goto_definition_inner( _state: &mut LspState, params: GotoDefinitionParams, + return_type_location_instead: bool, ) -> Result { let file_path = params.text_document_position_params.text_document.uri.to_file_path().map_err(|_| { @@ -65,8 +75,9 @@ fn on_goto_definition_inner( span: noirc_errors::Span::single_char(byte_index as u32), }; - let goto_definition_response = - interner.get_definition_location_from(search_for_location).and_then(|found_location| { + let goto_definition_response = interner + .get_definition_location_from(search_for_location, return_type_location_instead) + .and_then(|found_location| { let file_id = found_location.file; let definition_position = to_lsp_location(files, file_id, found_location.span)?; let response: GotoDefinitionResponse = diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index 9a4738e198..a03ee829e4 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -5,7 +5,7 @@ use async_lsp::ResponseError; use fm::codespan_files::Error; use lsp_types::{ DeclarationCapability, Location, Position, TextDocumentSyncCapability, TextDocumentSyncKind, - Url, + TypeDefinitionProviderCapability, Url, }; use nargo_fmt::Config; use serde::{Deserialize, Serialize}; @@ -35,7 +35,8 @@ mod tests; pub(crate) use { code_lens_request::collect_lenses_for_package, code_lens_request::on_code_lens_request, goto_declaration::on_goto_declaration_request, goto_definition::on_goto_definition_request, - profile_run::on_profile_run_request, test_run::on_test_run_request, tests::on_tests_request, + goto_definition::on_goto_type_definition_request, profile_run::on_profile_run_request, + test_run::on_test_run_request, tests::on_tests_request, }; /// LSP client will send initialization request after the server has started. @@ -94,6 +95,7 @@ pub(crate) fn on_initialize( nargo: Some(nargo), definition_provider: Some(lsp_types::OneOf::Left(true)), declaration_provider: Some(DeclarationCapability::Simple(true)), + type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), }, server_info: None, }) diff --git a/tooling/lsp/src/types.rs b/tooling/lsp/src/types.rs index 8dbc51ec83..e3492f2134 100644 --- a/tooling/lsp/src/types.rs +++ b/tooling/lsp/src/types.rs @@ -1,5 +1,7 @@ use fm::FileId; -use lsp_types::{DeclarationCapability, DefinitionOptions, OneOf}; +use lsp_types::{ + DeclarationCapability, DefinitionOptions, OneOf, TypeDefinitionProviderCapability, +}; use noirc_driver::DebugFile; use noirc_errors::{debug_info::OpCodesCount, Location}; use noirc_frontend::graph::CrateName; @@ -25,7 +27,8 @@ pub(crate) mod request { // Re-providing lsp_types that we don't need to override pub(crate) use lsp_types::request::{ - CodeLensRequest as CodeLens, Formatting, GotoDeclaration, GotoDefinition, Shutdown, + CodeLensRequest as CodeLens, Formatting, GotoDeclaration, GotoDefinition, + GotoTypeDefinition, Shutdown, }; #[derive(Debug)] @@ -118,6 +121,10 @@ pub(crate) struct ServerCapabilities { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) definition_provider: Option>, + /// The server provides goto type definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) type_definition_provider: Option, + /// The server provides code lens. #[serde(skip_serializing_if = "Option::is_none")] pub(crate) code_lens_provider: Option,