Skip to content

internal: Render sigantures with view hir command #19573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/hir-def/src/expr_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
107 changes: 96 additions & 11 deletions crates/hir-def/src/expr_store/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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::*;

Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
31 changes: 30 additions & 1 deletion crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
11 changes: 5 additions & 6 deletions crates/hir/src/semantics/source_to_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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 {
Expand All @@ -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),
Expand All @@ -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 => {
Expand All @@ -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(
Expand Down
12 changes: 6 additions & 6 deletions crates/hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand All @@ -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>>,
Expand Down Expand Up @@ -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,
}
}
Expand All @@ -159,7 +159,7 @@ impl SourceAnalyzer {
SourceAnalyzer {
resolver,
body_or_sig: Some(BodyOrSig::VariantFields {
_def: def,
def,
store: fields.store.clone(),
source_map,
}),
Expand Down
27 changes: 8 additions & 19 deletions crates/ide/src/view_hir.rs
Original file line number Diff line number Diff line change
@@ -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
//
Expand All @@ -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())
}