diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 3c83231cf1c3..62eccf4752d1 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -39,7 +39,7 @@ use hir_ty::{ TyDefId, TyKind, TypeCtor, }; use rustc_hash::FxHashSet; -use stdx::impl_from; +use stdx::{format_to, impl_from}; use syntax::{ ast::{self, AttrsOwner, NameOwner}, AstNode, SmolStr, @@ -797,6 +797,19 @@ impl Function { pub fn has_body(self, db: &dyn HirDatabase) -> bool { db.function_data(self.id).has_body } + + /// A textual representation of the HIR of this function for debugging purposes. + pub fn debug_hir(self, db: &dyn HirDatabase) -> String { + let body = db.body(self.id.into()); + + let mut result = String::new(); + format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); + for (id, expr) in body.exprs.iter() { + format_to!(result, "{:?}: {:?}\n", id, expr); + } + + result + } } // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b3331f03f151..a450794f3be2 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -31,6 +31,7 @@ mod folding_ranges; mod goto_definition; mod goto_implementation; mod goto_type_definition; +mod view_hir; mod hover; mod inlay_hints; mod join_lines; @@ -271,6 +272,10 @@ impl Analysis { self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) } + pub fn view_hir(&self, position: FilePosition) -> Cancelable { + self.with_db(|db| view_hir::view_hir(&db, position)) + } + pub fn expand_macro(&self, position: FilePosition) -> Cancelable> { self.with_db(|db| expand_macro::expand_macro(db, position)) } diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs new file mode 100644 index 000000000000..cfcfb7cfbc00 --- /dev/null +++ b/crates/ide/src/view_hir.rs @@ -0,0 +1,25 @@ +use hir::{Function, Semantics}; +use ide_db::base_db::FilePosition; +use ide_db::RootDatabase; +use syntax::{algo::find_node_at_offset, ast, AstNode}; + +// Feature: View Hir +// +// |=== +// | Editor | Action Name +// +// | VS Code | **Rust Analyzer: View Hir** +// |=== +pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { + body_hir(db, position).unwrap_or("Not inside a function body".to_string()) +} + +fn body_hir(db: &RootDatabase, position: FilePosition) -> Option { + let sema = Semantics::new(db); + let source_file = sema.parse(position.file_id); + + let function = find_node_at_offset::(source_file.syntax(), position.offset)?; + + let function: Function = sema.to_def(&function)?; + Some(function.debug_hir(db)) +} diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 948cfc17ce94..dd486070b917 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -105,6 +105,16 @@ pub(crate) fn handle_syntax_tree( Ok(res) } +pub(crate) fn handle_view_hir( + snap: GlobalStateSnapshot, + params: lsp_types::TextDocumentPositionParams, +) -> Result { + let _p = profile::span("handle_view_hir"); + let position = from_proto::file_position(&snap, params)?; + let res = snap.analysis.view_hir(position)?; + Ok(res) +} + pub(crate) fn handle_expand_macro( snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 93ac45415fbe..a85978737b3a 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -53,6 +53,14 @@ pub struct SyntaxTreeParams { pub range: Option, } +pub enum ViewHir {} + +impl Request for ViewHir { + type Params = lsp_types::TextDocumentPositionParams; + type Result = String; + const METHOD: &'static str = "rust-analyzer/viewHir"; +} + pub enum ExpandMacro {} impl Request for ExpandMacro { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 5d55dc96e2a1..8eca79f7ee40 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -443,6 +443,7 @@ impl GlobalState { .on_sync::(|s, p| handlers::handle_memory_usage(s, p))? .on::(handlers::handle_analyzer_status) .on::(handlers::handle_syntax_tree) + .on::(handlers::handle_view_hir) .on::(handlers::handle_expand_macro) .on::(handlers::handle_parent_module) .on::(handlers::handle_runnables) diff --git a/docs/dev/README.md b/docs/dev/README.md index 4a2f9feb3691..55527bab0aae 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -227,6 +227,8 @@ There are also two VS Code commands which might be of interest: * `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. +* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. + You can hover over syntax nodes in the opened text file to see the appropriate rust code that it refers to and the rust editor will also highlight the proper text range. diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8c01db07c849..78d86f060a67 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@