mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +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; | ||||
| pub mod lower; | ||||
| pub mod path; | ||||
| pub(crate) mod pretty; | ||||
| pub mod pretty; | ||||
| pub mod scope; | ||||
| #[cfg(test)] | ||||
| mod tests; | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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( | ||||
|  |  | |||
|  | @ -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, | ||||
|             }), | ||||
|  |  | |||
|  | @ -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}; | |||
| //
 | ||||
| // 
 | ||||
| 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()) | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth