diff options
| author | geetanshjuneja <ronitjuneja2002@gmail.com> | 2025-03-10 18:05:10 +0530 |
|---|---|---|
| committer | geetanshjuneja <ronitjuneja2002@gmail.com> | 2025-04-07 21:14:01 +0530 |
| commit | ac3a2b9ca931dad54a190df9bf91d193aaf9f67a (patch) | |
| tree | c091e61072131c5f2ff3f9d5232d9dbfd2c26d30 /src/tools/rust-analyzer | |
| parent | 50f3e01399ca15ed582e62c040a21ad4aee494c8 (diff) | |
| download | rust-ac3a2b9ca931dad54a190df9bf91d193aaf9f67a.tar.gz rust-ac3a2b9ca931dad54a190df9bf91d193aaf9f67a.zip | |
added children modules
Diffstat (limited to 'src/tools/rust-analyzer')
10 files changed, 196 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/children_modules.rs b/src/tools/rust-analyzer/crates/ide/src/children_modules.rs new file mode 100644 index 00000000000..a668e52c3c9 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/children_modules.rs @@ -0,0 +1,116 @@ +use hir::Semantics; +use ide_db::{FilePosition, RootDatabase}; +use syntax::{ + algo::find_node_at_offset, + ast::{self, AstNode}, +}; + +use crate::NavigationTarget; + +/// This returns `Vec` because a module may be included from several places. +pub(crate) fn children_modules(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { + let sema = Semantics::new(db); + let source_file = sema.parse_guess_edition(position.file_id); + // First go to the parent module which contains the cursor + let module = find_node_at_offset::<ast::Module>(source_file.syntax(), position.offset); + + match module { + Some(module) => { + // Return all the children module inside the ItemList of the parent module + sema.to_def(&module) + .into_iter() + .flat_map(|module| module.children(db)) + .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site()) + .collect() + } + None => { + // Return all the children module inside the source file + sema.file_to_module_defs(position.file_id) + .flat_map(|module| module.children(db)) + .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site()) + .collect() + } + } +} + +#[cfg(test)] +mod tests { + use ide_db::FileRange; + + use crate::fixture; + + fn check_children_module(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + let (analysis, position, expected) = fixture::annotations(ra_fixture); + let navs = analysis.children_modules(position).unwrap(); + let navs = navs + .iter() + .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) + .collect::<Vec<_>>(); + assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs); + } + + #[test] + fn test_resolve_children_module() { + check_children_module( + r#" +//- /lib.rs +$0 +mod foo; + //^^^ + +//- /foo.rs +// empty +"#, + ); + } + + #[test] + fn test_resolve_children_module_on_module_decl() { + check_children_module( + r#" +//- /lib.rs +mod $0foo; +//- /foo.rs +mod bar; + //^^^ + +//- /foo/bar.rs +// empty +"#, + ); + } + + #[test] + fn test_resolve_children_module_for_inline() { + check_children_module( + r#" +//- /lib.rs +mod foo { + mod $0bar { + mod baz {} + } //^^^ +} +"#, + ); + } + + #[test] + fn test_resolve_multi_child_module() { + check_children_module( + r#" +//- /main.rs +$0 +mod foo; + //^^^ +mod bar; + //^^^ + +//- /foo.rs +// empty + +//- /bar.rs +// empty +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 13b161e59d9..a517dd0381d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -20,6 +20,7 @@ mod navigation_target; mod annotations; mod call_hierarchy; +mod children_modules; mod doc_links; mod expand_macro; mod extend_selection; @@ -605,6 +606,11 @@ impl Analysis { self.with_db(|db| parent_module::parent_module(db, position)) } + /// Returns vec of `mod name;` declaration which are created by the current module. + pub fn children_modules(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> { + self.with_db(|db| children_modules::children_modules(db, position)) + } + /// Returns crates that this file belongs to. pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> { self.with_db(|db| parent_module::crates_for(db, file_id)) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 75fe99e95d9..0444a0ebf6a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -943,6 +943,18 @@ pub(crate) fn handle_parent_module( Ok(Some(res)) } +pub(crate) fn handle_children_modules( + snap: GlobalStateSnapshot, + params: lsp_types::TextDocumentPositionParams, +) -> anyhow::Result<Option<lsp_types::GotoDefinitionResponse>> { + let _p = tracing::info_span!("handle_children_module").entered(); + // locate children module by semantics + let position = try_default!(from_proto::file_position(&snap, params)?); + let navs = snap.analysis.children_modules(position)?; + let res = to_proto::goto_definition_response(&snap, None, navs)?; + Ok(Some(res)) +} + pub(crate) fn handle_runnables( snap: GlobalStateSnapshot, params: lsp_ext::RunnablesParams, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 7fa8e488b5c..e751e7da70e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -157,6 +157,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { "onEnter": true, "openCargoToml": true, "parentModule": true, + "childrenModules": true, "runnables": { "kinds": [ "cargo" ], }, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 876a0db8e11..ae4a9dbe19e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -399,6 +399,14 @@ impl Request for ParentModule { const METHOD: &'static str = "experimental/parentModule"; } +pub enum ChildrenModules {} + +impl Request for ChildrenModules { + type Params = lsp_types::TextDocumentPositionParams; + type Result = Option<lsp_types::GotoDefinitionResponse>; + const METHOD: &'static str = "experimental/childrenModule"; +} + pub enum JoinLines {} impl Request for JoinLines { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 47fcb5ac02b..0b5d040df20 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -1172,6 +1172,7 @@ impl GlobalState { .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function) .on::<NO_RETRY, lsp_ext::ExpandMacro>(handlers::handle_expand_macro) .on::<NO_RETRY, lsp_ext::ParentModule>(handlers::handle_parent_module) + .on::<NO_RETRY, lsp_ext::ChildrenModules>(handlers::handle_children_modules) .on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables) .on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests) .on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action) diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a04886270b4..daabab49ece 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -171,6 +171,11 @@ "category": "rust-analyzer" }, { + "command": "rust-analyzer.childrenModules", + "title": "Locate children modules", + "category": "rust-analyzer" + }, + { "command": "rust-analyzer.joinLines", "title": "Join lines", "category": "rust-analyzer" @@ -3374,6 +3379,10 @@ "when": "inRustProject" }, { + "command": "rust-analyzer.childrenModule", + "when": "inRustProject" + }, + { "command": "rust-analyzer.joinLines", "when": "inRustProject" }, diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 4e614d32057..a78e935152c 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -266,6 +266,43 @@ export function parentModule(ctx: CtxInit): Cmd { }; } +export function childrenModules(ctx: CtxInit): Cmd { + return async () => { + const editor = vscode.window.activeTextEditor; + if (!editor) return; + if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return; + + const client = ctx.client; + + const locations = await client.sendRequest(ra.childrenModules, { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }); + if (!locations) return; + + if (locations.length === 1) { + const loc = unwrapUndefinable(locations[0]); + + const uri = client.protocol2CodeConverter.asUri(loc.targetUri); + const range = client.protocol2CodeConverter.asRange(loc.targetRange); + + const doc = await vscode.workspace.openTextDocument(uri); + const e = await vscode.window.showTextDocument(doc); + e.selection = new vscode.Selection(range.start, range.start); + e.revealRange(range, vscode.TextEditorRevealType.InCenter); + } else { + const uri = editor.document.uri.toString(); + const position = client.code2ProtocolConverter.asPosition(editor.selection.active); + await showReferencesImpl( + client, + uri, + position, + locations.map((loc) => lc.Location.create(loc.targetUri, loc.targetRange)), + ); + } + }; +} + export function openCargoToml(ctx: CtxInit): Cmd { return async () => { const editor = ctx.activeRustEditor; diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts index af5129ac963..1cf55f6613a 100644 --- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts +++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts @@ -194,6 +194,11 @@ export const parentModule = new lc.RequestType< lc.LocationLink[] | null, void >("experimental/parentModule"); +export const childrenModules = new lc.RequestType< + lc.TextDocumentPositionParams, + lc.LocationLink[] | null, + void +>("experimental/childrenModule"); export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>( "experimental/runnables", ); diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 451294e26f6..95a52d710cc 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -158,6 +158,7 @@ function createCommands(): Record<string, CommandFactory> { matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, parentModule: { enabled: commands.parentModule }, + childrenModules: { enabled: commands.childrenModules }, viewHir: { enabled: commands.viewHir }, viewMir: { enabled: commands.viewMir }, interpretFunction: { enabled: commands.interpretFunction }, |
