about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs107
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_hir.rs27
6 files changed, 146 insertions, 44 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index eb66e592d68..9349ee77405 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -4,7 +4,7 @@ pub mod body;
 mod expander;
 pub mod lower;
 pub mod path;
-pub(crate) mod pretty;
+pub mod pretty;
 pub mod scope;
 #[cfg(test)]
 mod tests;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index 01476deb623..5e3580e590e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -10,8 +10,9 @@ use hir_expand::{Lookup, mod_path::PathKind};
 use itertools::Itertools;
 use span::Edition;
 
+use crate::signatures::StructFlags;
 use crate::{
-    DefWithBodyId, ItemTreeLoc, TypeParamId,
+    AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId,
     expr_store::path::{GenericArg, GenericArgs},
     hir::{
         Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
@@ -21,6 +22,7 @@ use crate::{
     signatures::{FnFlags, FunctionSignature, StructSignature},
     type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
 };
+use crate::{item_tree::FieldsShape, signatures::FieldData};
 
 use super::*;
 
@@ -40,13 +42,13 @@ macro_rules! wln {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum LineFormat {
+pub enum LineFormat {
     Oneline,
     Newline,
     Indentation,
 }
 
-pub(crate) fn print_body_hir(
+pub fn print_body_hir(
     db: &dyn DefDatabase,
     body: &Body,
     owner: DefWithBodyId,
@@ -112,7 +114,93 @@ pub(crate) fn print_body_hir(
     p.buf
 }
 
-pub(crate) fn print_path(
+pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String {
+    let header = match owner {
+        VariantId::StructId(it) => {
+            it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition)))
+        }
+        VariantId::EnumVariantId(enum_variant_id) => {
+            let loc = enum_variant_id.lookup(db);
+            let enum_loc = loc.parent.lookup(db);
+            format!(
+                "enum {}::{}",
+                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
+                loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
+            )
+        }
+        VariantId::UnionId(union_id) => union_id
+            .lookup(db)
+            .id
+            .resolved(db, |it| format!("union {}", it.name.display(db, edition))),
+    };
+
+    let fields = db.variant_fields(owner);
+
+    let mut p = Printer {
+        db,
+        store: &fields.store,
+        buf: header,
+        indent_level: 0,
+        line_format: LineFormat::Newline,
+        edition,
+    };
+    match fields.shape {
+        FieldsShape::Record => wln!(p, " {{"),
+        FieldsShape::Tuple => wln!(p, "("),
+        FieldsShape::Unit => (),
+    }
+
+    for (_, data) in fields.fields().iter() {
+        let FieldData { name, type_ref, visibility, is_unsafe } = data;
+        match visibility {
+            crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => {
+                w!(p, "{}", interned.display(db, p.edition))
+            }
+            crate::item_tree::RawVisibility::Public => w!(p, "pub "),
+        }
+        if *is_unsafe {
+            w!(p, "unsafe ");
+        }
+        w!(p, "{}: ", name.display(db, p.edition));
+        p.print_type_ref(*type_ref);
+    }
+
+    match fields.shape {
+        FieldsShape::Record => wln!(p, "}}"),
+        FieldsShape::Tuple => wln!(p, ");"),
+        FieldsShape::Unit => wln!(p, ";"),
+    }
+    p.buf
+}
+
+pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Edition) -> String {
+    match owner {
+        GenericDefId::AdtId(id) => match id {
+            AdtId::StructId(id) => {
+                let signature = db.struct_signature(id);
+                print_struct(db, &signature, edition)
+            }
+            AdtId::UnionId(id) => {
+                format!("unimplemented {id:?}")
+            }
+            AdtId::EnumId(id) => {
+                format!("unimplemented {id:?}")
+            }
+        },
+        GenericDefId::ConstId(id) => format!("unimplemented {id:?}"),
+        GenericDefId::FunctionId(id) => {
+            let signature = db.function_signature(id);
+            print_function(db, &signature, edition)
+        }
+        GenericDefId::ImplId(id) => format!("unimplemented {id:?}"),
+        GenericDefId::StaticId(id) => format!("unimplemented {id:?}"),
+        GenericDefId::TraitAliasId(id) => format!("unimplemented {id:?}"),
+        GenericDefId::TraitId(id) => format!("unimplemented {id:?}"),
+        GenericDefId::TypeAliasId(id) => format!("unimplemented {id:?}"),
+    }
+}
+
+pub fn print_path(
     db: &dyn DefDatabase,
     store: &ExpressionStore,
     path: &Path,
@@ -130,14 +218,11 @@ pub(crate) fn print_path(
     p.buf
 }
 
-pub(crate) fn print_struct(
+pub fn print_struct(
     db: &dyn DefDatabase,
     StructSignature { name, generic_params, store, flags, shape, repr }: &StructSignature,
     edition: Edition,
 ) -> String {
-    use crate::item_tree::FieldsShape;
-    use crate::signatures::StructFlags;
-
     let mut p = Printer {
         db,
         store,
@@ -180,7 +265,7 @@ pub(crate) fn print_struct(
     p.buf
 }
 
-pub(crate) fn print_function(
+pub fn print_function(
     db: &dyn DefDatabase,
     FunctionSignature {
         name,
@@ -342,7 +427,7 @@ fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p:
     }
 }
 
-pub(crate) fn print_expr_hir(
+pub fn print_expr_hir(
     db: &dyn DefDatabase,
     store: &ExpressionStore,
     _owner: DefWithBodyId,
@@ -361,7 +446,7 @@ pub(crate) fn print_expr_hir(
     p.buf
 }
 
-pub(crate) fn print_pat_hir(
+pub fn print_pat_hir(
     db: &dyn DefDatabase,
     store: &ExpressionStore,
     _owner: DefWithBodyId,
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 39130d1659b..c0f99e09e37 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -20,7 +20,7 @@ use hir_def::{
     type_ref::Mutability,
 };
 use hir_expand::{
-    ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
+    ExpandResult, FileRange, HirFileIdExt, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
     attrs::collect_attrs,
     builtin::{BuiltinFnLikeExpander, EagerExpander},
     db::ExpandDatabase,
@@ -739,6 +739,35 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
+    pub fn debug_hir_at(&self, token: SyntaxToken) -> Option<String> {
+        self.analyze_no_infer(&token.parent()?).and_then(|it| {
+            Some(match it.body_or_sig.as_ref()? {
+                crate::source_analyzer::BodyOrSig::Body { def, body, .. } => {
+                    hir_def::expr_store::pretty::print_body_hir(
+                        self.db,
+                        body,
+                        *def,
+                        it.file_id.edition(self.db),
+                    )
+                }
+                &crate::source_analyzer::BodyOrSig::VariantFields { def, .. } => {
+                    hir_def::expr_store::pretty::print_variant_body_hir(
+                        self.db,
+                        def,
+                        it.file_id.edition(self.db),
+                    )
+                }
+                &crate::source_analyzer::BodyOrSig::Sig { def, .. } => {
+                    hir_def::expr_store::pretty::print_signature(
+                        self.db,
+                        def,
+                        it.file_id.edition(self.db),
+                    )
+                }
+            })
+        })
+    }
+
     /// Maps a node down by mapping its first and last token down.
     pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
         // This might not be the correct way to do this, but it works for now
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 06100b30f83..2f06a1dc681 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -220,7 +220,7 @@ impl SourceToDefCtx<'_, '_> {
     pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<ModuleId> {
         let _p = tracing::info_span!("module_to_def").entered();
         let parent_declaration = self
-            .ancestors_with_macros(src.syntax_ref(), |_, ancestor, _| {
+            .parent_ancestors_with_macros(src.syntax_ref(), |_, ancestor, _| {
                 ancestor.map(Either::<ast::Module, ast::BlockExpr>::cast).transpose()
             })
             .map(|it| it.transpose());
@@ -519,7 +519,7 @@ impl SourceToDefCtx<'_, '_> {
 
     pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
         let _p = tracing::info_span!("find_container").entered();
-        let def = self.ancestors_with_macros(src, |this, container, child| {
+        let def = self.parent_ancestors_with_macros(src, |this, container, child| {
             this.container_to_def(container, child)
         });
         if let Some(def) = def {
@@ -532,7 +532,7 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
-        self.ancestors_with_macros(src, |this, InFile { file_id, value }, _| {
+        self.parent_ancestors_with_macros(src, |this, InFile { file_id, value }, _| {
             let item = ast::Item::cast(value)?;
             match &item {
                 ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into),
@@ -555,7 +555,7 @@ impl SourceToDefCtx<'_, '_> {
 
     // FIXME: Remove this when we do inference in signatures
     fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
-        self.ancestors_with_macros(src, |this, InFile { file_id, value }, _| {
+        self.parent_ancestors_with_macros(src, |this, InFile { file_id, value }, _| {
             let item = match ast::Item::cast(value.clone()) {
                 Some(it) => it,
                 None => {
@@ -577,8 +577,7 @@ impl SourceToDefCtx<'_, '_> {
     }
 
     /// Skips the attributed item that caused the macro invocation we are climbing up
-    ///
-    fn ancestors_with_macros<T>(
+    fn parent_ancestors_with_macros<T>(
         &mut self,
         node: InFile<&SyntaxNode>,
         mut cb: impl FnMut(
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 6a39f9cab86..b86fe1fa393 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -60,11 +60,11 @@ use triomphe::Arc;
 pub(crate) struct SourceAnalyzer {
     pub(crate) file_id: HirFileId,
     pub(crate) resolver: Resolver,
-    body_or_sig: Option<BodyOrSig>,
+    pub(crate) body_or_sig: Option<BodyOrSig>,
 }
 
 #[derive(Debug)]
-enum BodyOrSig {
+pub(crate) enum BodyOrSig {
     Body {
         def: DefWithBodyId,
         body: Arc<Body>,
@@ -73,12 +73,12 @@ enum BodyOrSig {
     },
     // To be folded into body once it is considered one
     VariantFields {
-        _def: VariantId,
+        def: VariantId,
         store: Arc<ExpressionStore>,
         source_map: Arc<ExpressionStoreSourceMap>,
     },
     Sig {
-        _def: GenericDefId,
+        def: GenericDefId,
         store: Arc<ExpressionStore>,
         source_map: Arc<ExpressionStoreSourceMap>,
         // infer: Option<Arc<InferenceResult>>,
@@ -143,7 +143,7 @@ impl SourceAnalyzer {
         let resolver = def.resolver(db);
         SourceAnalyzer {
             resolver,
-            body_or_sig: Some(BodyOrSig::Sig { _def: def, store, source_map }),
+            body_or_sig: Some(BodyOrSig::Sig { def, store, source_map }),
             file_id,
         }
     }
@@ -159,7 +159,7 @@ impl SourceAnalyzer {
         SourceAnalyzer {
             resolver,
             body_or_sig: Some(BodyOrSig::VariantFields {
-                _def: def,
+                def,
                 store: fields.store.clone(),
                 source_map,
             }),
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
index 954917d4c09..ec5e993f5a6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
@@ -1,6 +1,6 @@
-use hir::{DefWithBody, Semantics};
+use hir::Semantics;
 use ide_db::{FilePosition, RootDatabase};
-use syntax::{AstNode, algo::ancestors_at_offset, ast};
+use syntax::AstNode;
 
 // Feature: View Hir
 //
@@ -10,21 +10,10 @@ use syntax::{AstNode, algo::ancestors_at_offset, ast};
 //
 // ![View Hir](https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif)
 pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
-    body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
-}
-
-fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
-    let sema = Semantics::new(db);
-    let source_file = sema.parse_guess_edition(position.file_id);
-
-    let item = ancestors_at_offset(source_file.syntax(), position.offset)
-        .filter(|it| !ast::MacroCall::can_cast(it.kind()))
-        .find_map(ast::Item::cast)?;
-    let def: DefWithBody = match item {
-        ast::Item::Fn(it) => sema.to_def(&it)?.into(),
-        ast::Item::Const(it) => sema.to_def(&it)?.into(),
-        ast::Item::Static(it) => sema.to_def(&it)?.into(),
-        _ => return None,
-    };
-    Some(def.debug_hir(db))
+    (|| {
+        let sema = Semantics::new(db);
+        let source_file = sema.parse_guess_edition(position.file_id);
+        sema.debug_hir_at(source_file.syntax().token_at_offset(position.offset).next()?)
+    })()
+    .unwrap_or_else(|| "Not inside a lowerable item".to_owned())
 }