mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
internal: Render sigantures with view hir command
This commit is contained in:
parent
afc367b96c
commit
40076b577f
@ -4,7 +4,7 @@ pub mod body;
|
|||||||
mod expander;
|
mod expander;
|
||||||
pub mod lower;
|
pub mod lower;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub(crate) mod pretty;
|
pub mod pretty;
|
||||||
pub mod scope;
|
pub mod scope;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -10,8 +10,9 @@ use hir_expand::{Lookup, mod_path::PathKind};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use span::Edition;
|
use span::Edition;
|
||||||
|
|
||||||
|
use crate::signatures::StructFlags;
|
||||||
use crate::{
|
use crate::{
|
||||||
DefWithBodyId, ItemTreeLoc, TypeParamId,
|
AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId,
|
||||||
expr_store::path::{GenericArg, GenericArgs},
|
expr_store::path::{GenericArg, GenericArgs},
|
||||||
hir::{
|
hir::{
|
||||||
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
|
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
|
||||||
@ -21,6 +22,7 @@ use crate::{
|
|||||||
signatures::{FnFlags, FunctionSignature, StructSignature},
|
signatures::{FnFlags, FunctionSignature, StructSignature},
|
||||||
type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
|
type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
|
||||||
};
|
};
|
||||||
|
use crate::{item_tree::FieldsShape, signatures::FieldData};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -40,13 +42,13 @@ macro_rules! wln {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum LineFormat {
|
pub enum LineFormat {
|
||||||
Oneline,
|
Oneline,
|
||||||
Newline,
|
Newline,
|
||||||
Indentation,
|
Indentation,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_body_hir(
|
pub fn print_body_hir(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
owner: DefWithBodyId,
|
owner: DefWithBodyId,
|
||||||
@ -112,7 +114,93 @@ pub(crate) fn print_body_hir(
|
|||||||
p.buf
|
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,
|
db: &dyn DefDatabase,
|
||||||
store: &ExpressionStore,
|
store: &ExpressionStore,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@ -130,14 +218,11 @@ pub(crate) fn print_path(
|
|||||||
p.buf
|
p.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_struct(
|
pub fn print_struct(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
StructSignature { name, generic_params, store, flags, shape, repr }: &StructSignature,
|
StructSignature { name, generic_params, store, flags, shape, repr }: &StructSignature,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
) -> String {
|
) -> String {
|
||||||
use crate::item_tree::FieldsShape;
|
|
||||||
use crate::signatures::StructFlags;
|
|
||||||
|
|
||||||
let mut p = Printer {
|
let mut p = Printer {
|
||||||
db,
|
db,
|
||||||
store,
|
store,
|
||||||
@ -180,7 +265,7 @@ pub(crate) fn print_struct(
|
|||||||
p.buf
|
p.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_function(
|
pub fn print_function(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
FunctionSignature {
|
FunctionSignature {
|
||||||
name,
|
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,
|
db: &dyn DefDatabase,
|
||||||
store: &ExpressionStore,
|
store: &ExpressionStore,
|
||||||
_owner: DefWithBodyId,
|
_owner: DefWithBodyId,
|
||||||
@ -361,7 +446,7 @@ pub(crate) fn print_expr_hir(
|
|||||||
p.buf
|
p.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_pat_hir(
|
pub fn print_pat_hir(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
store: &ExpressionStore,
|
store: &ExpressionStore,
|
||||||
_owner: DefWithBodyId,
|
_owner: DefWithBodyId,
|
||||||
|
@ -20,7 +20,7 @@ use hir_def::{
|
|||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
};
|
};
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
|
ExpandResult, FileRange, HirFileIdExt, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
|
||||||
attrs::collect_attrs,
|
attrs::collect_attrs,
|
||||||
builtin::{BuiltinFnLikeExpander, EagerExpander},
|
builtin::{BuiltinFnLikeExpander, EagerExpander},
|
||||||
db::ExpandDatabase,
|
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.
|
/// 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]> {
|
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
|
// This might not be the correct way to do this, but it works for now
|
||||||
|
@ -220,7 +220,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||||||
pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<ModuleId> {
|
pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<ModuleId> {
|
||||||
let _p = tracing::info_span!("module_to_def").entered();
|
let _p = tracing::info_span!("module_to_def").entered();
|
||||||
let parent_declaration = self
|
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()
|
ancestor.map(Either::<ast::Module, ast::BlockExpr>::cast).transpose()
|
||||||
})
|
})
|
||||||
.map(|it| it.transpose());
|
.map(|it| it.transpose());
|
||||||
@ -519,7 +519,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||||||
|
|
||||||
pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
|
pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
|
||||||
let _p = tracing::info_span!("find_container").entered();
|
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)
|
this.container_to_def(container, child)
|
||||||
});
|
});
|
||||||
if let Some(def) = def {
|
if let Some(def) = def {
|
||||||
@ -532,7 +532,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
|
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)?;
|
let item = ast::Item::cast(value)?;
|
||||||
match &item {
|
match &item {
|
||||||
ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into),
|
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
|
// FIXME: Remove this when we do inference in signatures
|
||||||
fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
|
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()) {
|
let item = match ast::Item::cast(value.clone()) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
@ -577,8 +577,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Skips the attributed item that caused the macro invocation we are climbing up
|
/// Skips the attributed item that caused the macro invocation we are climbing up
|
||||||
///
|
fn parent_ancestors_with_macros<T>(
|
||||||
fn ancestors_with_macros<T>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
node: InFile<&SyntaxNode>,
|
node: InFile<&SyntaxNode>,
|
||||||
mut cb: impl FnMut(
|
mut cb: impl FnMut(
|
||||||
|
@ -60,11 +60,11 @@ use triomphe::Arc;
|
|||||||
pub(crate) struct SourceAnalyzer {
|
pub(crate) struct SourceAnalyzer {
|
||||||
pub(crate) file_id: HirFileId,
|
pub(crate) file_id: HirFileId,
|
||||||
pub(crate) resolver: Resolver,
|
pub(crate) resolver: Resolver,
|
||||||
body_or_sig: Option<BodyOrSig>,
|
pub(crate) body_or_sig: Option<BodyOrSig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum BodyOrSig {
|
pub(crate) enum BodyOrSig {
|
||||||
Body {
|
Body {
|
||||||
def: DefWithBodyId,
|
def: DefWithBodyId,
|
||||||
body: Arc<Body>,
|
body: Arc<Body>,
|
||||||
@ -73,12 +73,12 @@ enum BodyOrSig {
|
|||||||
},
|
},
|
||||||
// To be folded into body once it is considered one
|
// To be folded into body once it is considered one
|
||||||
VariantFields {
|
VariantFields {
|
||||||
_def: VariantId,
|
def: VariantId,
|
||||||
store: Arc<ExpressionStore>,
|
store: Arc<ExpressionStore>,
|
||||||
source_map: Arc<ExpressionStoreSourceMap>,
|
source_map: Arc<ExpressionStoreSourceMap>,
|
||||||
},
|
},
|
||||||
Sig {
|
Sig {
|
||||||
_def: GenericDefId,
|
def: GenericDefId,
|
||||||
store: Arc<ExpressionStore>,
|
store: Arc<ExpressionStore>,
|
||||||
source_map: Arc<ExpressionStoreSourceMap>,
|
source_map: Arc<ExpressionStoreSourceMap>,
|
||||||
// infer: Option<Arc<InferenceResult>>,
|
// infer: Option<Arc<InferenceResult>>,
|
||||||
@ -143,7 +143,7 @@ impl SourceAnalyzer {
|
|||||||
let resolver = def.resolver(db);
|
let resolver = def.resolver(db);
|
||||||
SourceAnalyzer {
|
SourceAnalyzer {
|
||||||
resolver,
|
resolver,
|
||||||
body_or_sig: Some(BodyOrSig::Sig { _def: def, store, source_map }),
|
body_or_sig: Some(BodyOrSig::Sig { def, store, source_map }),
|
||||||
file_id,
|
file_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ impl SourceAnalyzer {
|
|||||||
SourceAnalyzer {
|
SourceAnalyzer {
|
||||||
resolver,
|
resolver,
|
||||||
body_or_sig: Some(BodyOrSig::VariantFields {
|
body_or_sig: Some(BodyOrSig::VariantFields {
|
||||||
_def: def,
|
def,
|
||||||
store: fields.store.clone(),
|
store: fields.store.clone(),
|
||||||
source_map,
|
source_map,
|
||||||
}),
|
}),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use hir::{DefWithBody, Semantics};
|
use hir::Semantics;
|
||||||
use ide_db::{FilePosition, RootDatabase};
|
use ide_db::{FilePosition, RootDatabase};
|
||||||
use syntax::{AstNode, algo::ancestors_at_offset, ast};
|
use syntax::AstNode;
|
||||||
|
|
||||||
// Feature: View Hir
|
// Feature: View Hir
|
||||||
//
|
//
|
||||||
@ -10,21 +10,10 @@ use syntax::{AstNode, algo::ancestors_at_offset, ast};
|
|||||||
//
|
//
|
||||||
// 
|
// 
|
||||||
pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
|
pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
|
||||||
body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
|
(|| {
|
||||||
}
|
let sema = Semantics::new(db);
|
||||||
|
let source_file = sema.parse_guess_edition(position.file_id);
|
||||||
fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
|
sema.debug_hir_at(source_file.syntax().token_at_offset(position.offset).next()?)
|
||||||
let sema = Semantics::new(db);
|
})()
|
||||||
let source_file = sema.parse_guess_edition(position.file_id);
|
.unwrap_or_else(|| "Not inside a lowerable item".to_owned())
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user