mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Merge pull request #19573 from Veykril/push-swrzvrroornr
internal: Render sigantures with view hir command
This commit is contained in:
		
						commit
						8365cf853e
					
				
					 6 changed files with 146 additions and 44 deletions
				
			
		|  | @ -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()) |     (|| { | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> { |  | ||||||
|         let sema = Semantics::new(db); |         let sema = Semantics::new(db); | ||||||
|         let source_file = sema.parse_guess_edition(position.file_id); |         let source_file = sema.parse_guess_edition(position.file_id); | ||||||
| 
 |         sema.debug_hir_at(source_file.syntax().token_at_offset(position.offset).next()?) | ||||||
|     let item = ancestors_at_offset(source_file.syntax(), position.offset) |     })() | ||||||
|         .filter(|it| !ast::MacroCall::can_cast(it.kind())) |     .unwrap_or_else(|| "Not inside a lowerable item".to_owned()) | ||||||
|         .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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth