diff options
author | oxalica <[email protected]> | 2021-03-14 12:03:39 +0000 |
---|---|---|
committer | oxalica <[email protected]> | 2021-03-15 17:04:20 +0000 |
commit | ef416e0154767619fcbfa0d1682b28bd338a8ce9 (patch) | |
tree | e73269dbb569f176e9bba1b16eb74731d63c94c2 | |
parent | 2bb8956a102cb2efbea35e414a8214fba2efcaf6 (diff) |
Impl HirDisplay for function hover message
-rw-r--r-- | crates/hir/src/display.rs | 234 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 11 | ||||
-rw-r--r-- | crates/hir_ty/src/display.rs | 203 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 10 |
5 files changed, 461 insertions, 14 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 86f48256e..ae08e2584 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -1,9 +1,120 @@ | |||
1 | //! HirDisplay implementations for various hir types. | 1 | //! HirDisplay implementations for various hir types. |
2 | use hir_def::{ | ||
3 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, | ||
4 | type_ref::{TypeBound, TypeRef}, | ||
5 | GenericDefId, | ||
6 | }; | ||
2 | use hir_ty::display::{ | 7 | use hir_ty::display::{ |
3 | write_bounds_like_dyn_trait_with_prefix, HirDisplay, HirDisplayError, HirFormatter, | 8 | write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, |
9 | HirFormatter, | ||
4 | }; | 10 | }; |
11 | use syntax::ast::{self, NameOwner}; | ||
12 | |||
13 | use crate::{Function, HasVisibility, Substs, Type, TypeParam}; | ||
14 | |||
15 | impl HirDisplay for Function { | ||
16 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
17 | let data = f.db.function_data(self.id); | ||
18 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
19 | let qual = &data.qualifier; | ||
20 | if qual.is_default { | ||
21 | write!(f, "default ")?; | ||
22 | } | ||
23 | if qual.is_const { | ||
24 | write!(f, "const ")?; | ||
25 | } | ||
26 | if qual.is_async { | ||
27 | write!(f, "async ")?; | ||
28 | } | ||
29 | if qual.is_unsafe { | ||
30 | write!(f, "unsafe ")?; | ||
31 | } | ||
32 | if let Some(abi) = &qual.abi { | ||
33 | // FIXME: String escape? | ||
34 | write!(f, "extern \"{}\" ", abi)?; | ||
35 | } | ||
36 | write!(f, "fn {}", data.name)?; | ||
37 | |||
38 | write_generic_params(GenericDefId::FunctionId(self.id), f)?; | ||
39 | |||
40 | write!(f, "(")?; | ||
5 | 41 | ||
6 | use crate::{Substs, Type, TypeParam}; | 42 | let write_self_param = |ty: &TypeRef, f: &mut HirFormatter| match ty { |
43 | TypeRef::Path(p) if p.is_self_type() => write!(f, "self"), | ||
44 | TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) => | ||
45 | { | ||
46 | write!(f, "&")?; | ||
47 | if let Some(lifetime) = lifetime { | ||
48 | write!(f, "{} ", lifetime.name)?; | ||
49 | } | ||
50 | if let hir_def::type_ref::Mutability::Mut = mut_ { | ||
51 | write!(f, "mut ")?; | ||
52 | } | ||
53 | write!(f, "self") | ||
54 | } | ||
55 | _ => { | ||
56 | write!(f, "self: ")?; | ||
57 | ty.hir_fmt(f) | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | let mut first = true; | ||
62 | for (param, type_ref) in self.assoc_fn_params(f.db).into_iter().zip(&data.params) { | ||
63 | if !first { | ||
64 | write!(f, ", ")?; | ||
65 | } else { | ||
66 | first = false; | ||
67 | if data.has_self_param { | ||
68 | write_self_param(type_ref, f)?; | ||
69 | continue; | ||
70 | } | ||
71 | } | ||
72 | match param.pattern_source(f.db) { | ||
73 | Some(ast::Pat::IdentPat(p)) if p.name().is_some() => { | ||
74 | write!(f, "{}: ", p.name().unwrap())? | ||
75 | } | ||
76 | _ => write!(f, "_: ")?, | ||
77 | } | ||
78 | // FIXME: Use resolved `param.ty` or raw `type_ref`? | ||
79 | // The former will ignore lifetime arguments currently. | ||
80 | type_ref.hir_fmt(f)?; | ||
81 | } | ||
82 | write!(f, ")")?; | ||
83 | |||
84 | // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns. | ||
85 | // Use ugly pattern match to strip the Future trait. | ||
86 | // Better way? | ||
87 | let ret_type = if !qual.is_async { | ||
88 | &data.ret_type | ||
89 | } else { | ||
90 | match &data.ret_type { | ||
91 | TypeRef::ImplTrait(bounds) => match &bounds[0] { | ||
92 | TypeBound::Path(path) => { | ||
93 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings | ||
94 | [0] | ||
95 | .type_ref | ||
96 | .as_ref() | ||
97 | .unwrap() | ||
98 | } | ||
99 | _ => panic!("Async fn ret_type should be impl Future"), | ||
100 | }, | ||
101 | _ => panic!("Async fn ret_type should be impl Future"), | ||
102 | } | ||
103 | }; | ||
104 | |||
105 | match ret_type { | ||
106 | TypeRef::Tuple(tup) if tup.is_empty() => {} | ||
107 | ty => { | ||
108 | write!(f, " -> ")?; | ||
109 | ty.hir_fmt(f)?; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | write_where_clause(GenericDefId::FunctionId(self.id), f)?; | ||
114 | |||
115 | Ok(()) | ||
116 | } | ||
117 | } | ||
7 | 118 | ||
8 | impl HirDisplay for Type { | 119 | impl HirDisplay for Type { |
9 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 120 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
@@ -23,3 +134,122 @@ impl HirDisplay for TypeParam { | |||
23 | Ok(()) | 134 | Ok(()) |
24 | } | 135 | } |
25 | } | 136 | } |
137 | |||
138 | fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
139 | let params = f.db.generic_params(def); | ||
140 | if params.lifetimes.is_empty() && params.types.is_empty() && params.consts.is_empty() { | ||
141 | return Ok(()); | ||
142 | } | ||
143 | write!(f, "<")?; | ||
144 | |||
145 | let mut first = true; | ||
146 | let mut delim = |f: &mut HirFormatter| { | ||
147 | if first { | ||
148 | first = false; | ||
149 | Ok(()) | ||
150 | } else { | ||
151 | write!(f, ", ") | ||
152 | } | ||
153 | }; | ||
154 | for (_, lifetime) in params.lifetimes.iter() { | ||
155 | delim(f)?; | ||
156 | write!(f, "{}", lifetime.name)?; | ||
157 | } | ||
158 | for (_, ty) in params.types.iter() { | ||
159 | if ty.provenance != TypeParamProvenance::TypeParamList { | ||
160 | continue; | ||
161 | } | ||
162 | if let Some(name) = &ty.name { | ||
163 | delim(f)?; | ||
164 | write!(f, "{}", name)?; | ||
165 | if let Some(default) = &ty.default { | ||
166 | write!(f, " = ")?; | ||
167 | default.hir_fmt(f)?; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | for (_, konst) in params.consts.iter() { | ||
172 | delim(f)?; | ||
173 | write!(f, "const {}: ", konst.name)?; | ||
174 | konst.ty.hir_fmt(f)?; | ||
175 | } | ||
176 | |||
177 | write!(f, ">")?; | ||
178 | Ok(()) | ||
179 | } | ||
180 | |||
181 | fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
182 | let params = f.db.generic_params(def); | ||
183 | if params.where_predicates.is_empty() { | ||
184 | return Ok(()); | ||
185 | } | ||
186 | |||
187 | let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target { | ||
188 | WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), | ||
189 | WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name { | ||
190 | Some(name) => write!(f, "{}", name), | ||
191 | None => write!(f, "{{unnamed}}"), | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | write!(f, "\nwhere")?; | ||
196 | |||
197 | for (pred_idx, pred) in params.where_predicates.iter().enumerate() { | ||
198 | let prev_pred = | ||
199 | if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) }; | ||
200 | |||
201 | let new_predicate = |f: &mut HirFormatter| { | ||
202 | write!(f, "{}", if pred_idx == 0 { "\n " } else { ",\n " }) | ||
203 | }; | ||
204 | |||
205 | match pred { | ||
206 | WherePredicate::TypeBound { target, bound } => { | ||
207 | if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target) | ||
208 | { | ||
209 | write!(f, " + ")?; | ||
210 | } else { | ||
211 | new_predicate(f)?; | ||
212 | write_target(target, f)?; | ||
213 | write!(f, ": ")?; | ||
214 | } | ||
215 | bound.hir_fmt(f)?; | ||
216 | } | ||
217 | WherePredicate::Lifetime { target, bound } => { | ||
218 | if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) | ||
219 | { | ||
220 | write!(f, " + {}", bound.name)?; | ||
221 | } else { | ||
222 | new_predicate(f)?; | ||
223 | write!(f, "{}: {}", target.name, bound.name)?; | ||
224 | } | ||
225 | } | ||
226 | WherePredicate::ForLifetime { lifetimes, target, bound } => { | ||
227 | if matches!( | ||
228 | prev_pred, | ||
229 | Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. }) | ||
230 | if lifetimes_ == lifetimes && target_ == target, | ||
231 | ) { | ||
232 | write!(f, " + ")?; | ||
233 | } else { | ||
234 | new_predicate(f)?; | ||
235 | write!(f, "for<")?; | ||
236 | for (idx, lifetime) in lifetimes.iter().enumerate() { | ||
237 | if idx != 0 { | ||
238 | write!(f, ", ")?; | ||
239 | } | ||
240 | write!(f, "{}", lifetime)?; | ||
241 | } | ||
242 | write!(f, "> ")?; | ||
243 | write_target(target, f)?; | ||
244 | write!(f, ": ")?; | ||
245 | } | ||
246 | bound.hir_fmt(f)?; | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // End of final predicate. There must be at least one predicate here. | ||
252 | write!(f, ",")?; | ||
253 | |||
254 | Ok(()) | ||
255 | } | ||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 0d0e757fc..476fdb132 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -822,7 +822,8 @@ impl Function { | |||
822 | db.function_data(self.id) | 822 | db.function_data(self.id) |
823 | .params | 823 | .params |
824 | .iter() | 824 | .iter() |
825 | .map(|type_ref| { | 825 | .enumerate() |
826 | .map(|(idx, type_ref)| { | ||
826 | let ty = Type { | 827 | let ty = Type { |
827 | krate, | 828 | krate, |
828 | ty: InEnvironment { | 829 | ty: InEnvironment { |
@@ -830,7 +831,7 @@ impl Function { | |||
830 | environment: environment.clone(), | 831 | environment: environment.clone(), |
831 | }, | 832 | }, |
832 | }; | 833 | }; |
833 | Param { ty } | 834 | Param { func: self, ty, idx } |
834 | }) | 835 | }) |
835 | .collect() | 836 | .collect() |
836 | } | 837 | } |
@@ -893,6 +894,9 @@ impl From<hir_ty::Mutability> for Access { | |||
893 | 894 | ||
894 | #[derive(Debug)] | 895 | #[derive(Debug)] |
895 | pub struct Param { | 896 | pub struct Param { |
897 | func: Function, | ||
898 | /// The index in parameter list, including self parameter. | ||
899 | idx: usize, | ||
896 | ty: Type, | 900 | ty: Type, |
897 | } | 901 | } |
898 | 902 | ||
@@ -900,6 +904,15 @@ impl Param { | |||
900 | pub fn ty(&self) -> &Type { | 904 | pub fn ty(&self) -> &Type { |
901 | &self.ty | 905 | &self.ty |
902 | } | 906 | } |
907 | |||
908 | pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> { | ||
909 | let params = self.func.source(db)?.value.param_list()?; | ||
910 | if params.self_param().is_some() { | ||
911 | params.params().nth(self.idx.checked_sub(1)?)?.pat() | ||
912 | } else { | ||
913 | params.params().nth(self.idx)?.pat() | ||
914 | } | ||
915 | } | ||
903 | } | 916 | } |
904 | 917 | ||
905 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 918 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 0e60dc2b6..8c923bb7b 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -9,7 +9,10 @@ use std::{ | |||
9 | 9 | ||
10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{hygiene::Hygiene, name::Name}; | 12 | use hir_expand::{ |
13 | hygiene::Hygiene, | ||
14 | name::{name, Name}, | ||
15 | }; | ||
13 | use syntax::ast; | 16 | use syntax::ast; |
14 | 17 | ||
15 | use crate::{ | 18 | use crate::{ |
@@ -209,6 +212,12 @@ impl Path { | |||
209 | }; | 212 | }; |
210 | Some(res) | 213 | Some(res) |
211 | } | 214 | } |
215 | |||
216 | pub fn is_self_type(&self) -> bool { | ||
217 | self.type_anchor.is_none() | ||
218 | && self.generic_args == &[None] | ||
219 | && self.mod_path.as_ident() == Some(&name!(Self)) | ||
220 | } | ||
212 | } | 221 | } |
213 | 222 | ||
214 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 223 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index c1062387e..c572bb114 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -5,7 +5,13 @@ use std::{borrow::Cow, fmt}; | |||
5 | use arrayvec::ArrayVec; | 5 | use arrayvec::ArrayVec; |
6 | use chalk_ir::Mutability; | 6 | use chalk_ir::Mutability; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, | 8 | db::DefDatabase, |
9 | find_path, | ||
10 | generics::TypeParamProvenance, | ||
11 | item_scope::ItemInNs, | ||
12 | path::{GenericArg, Path, PathKind}, | ||
13 | type_ref::{TypeBound, TypeRef}, | ||
14 | visibility::Visibility, | ||
9 | AssocContainerId, Lookup, ModuleId, TraitId, | 15 | AssocContainerId, Lookup, ModuleId, TraitId, |
10 | }; | 16 | }; |
11 | use hir_expand::name::Name; | 17 | use hir_expand::name::Name; |
@@ -232,7 +238,7 @@ where | |||
232 | 238 | ||
233 | const TYPE_HINT_TRUNCATION: &str = "…"; | 239 | const TYPE_HINT_TRUNCATION: &str = "…"; |
234 | 240 | ||
235 | impl HirDisplay for &Ty { | 241 | impl<T: HirDisplay> HirDisplay for &'_ T { |
236 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 242 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
237 | HirDisplay::hir_fmt(*self, f) | 243 | HirDisplay::hir_fmt(*self, f) |
238 | } | 244 | } |
@@ -761,12 +767,6 @@ impl HirDisplay for TraitRef { | |||
761 | } | 767 | } |
762 | } | 768 | } |
763 | 769 | ||
764 | impl HirDisplay for &GenericPredicate { | ||
765 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
766 | HirDisplay::hir_fmt(*self, f) | ||
767 | } | ||
768 | } | ||
769 | |||
770 | impl HirDisplay for GenericPredicate { | 770 | impl HirDisplay for GenericPredicate { |
771 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 771 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
772 | if f.should_truncate() { | 772 | if f.should_truncate() { |
@@ -825,3 +825,190 @@ impl HirDisplay for Obligation { | |||
825 | } | 825 | } |
826 | } | 826 | } |
827 | } | 827 | } |
828 | |||
829 | pub fn write_visibility( | ||
830 | module_id: ModuleId, | ||
831 | vis: Visibility, | ||
832 | f: &mut HirFormatter, | ||
833 | ) -> Result<(), HirDisplayError> { | ||
834 | match vis { | ||
835 | Visibility::Public => write!(f, "pub "), | ||
836 | Visibility::Module(vis_id) => { | ||
837 | let def_map = module_id.def_map(f.db.upcast()); | ||
838 | let root_module_id = def_map.module_id(def_map.root()); | ||
839 | if vis_id == module_id { | ||
840 | // pub(self) or omitted | ||
841 | Ok(()) | ||
842 | } else if root_module_id == vis_id { | ||
843 | write!(f, "pub(crate) ") | ||
844 | } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) { | ||
845 | write!(f, "pub(super) ") | ||
846 | } else { | ||
847 | write!(f, "pub(in ...) ") | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | |||
853 | impl HirDisplay for TypeRef { | ||
854 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
855 | match self { | ||
856 | TypeRef::Never => write!(f, "!")?, | ||
857 | TypeRef::Placeholder => write!(f, "_")?, | ||
858 | TypeRef::Tuple(elems) => { | ||
859 | write!(f, "(")?; | ||
860 | f.write_joined(elems, ", ")?; | ||
861 | if elems.len() == 1 { | ||
862 | write!(f, ",")?; | ||
863 | } | ||
864 | write!(f, ")")?; | ||
865 | } | ||
866 | TypeRef::Path(path) => path.hir_fmt(f)?, | ||
867 | TypeRef::RawPtr(inner, mutability) => { | ||
868 | let mutability = match mutability { | ||
869 | hir_def::type_ref::Mutability::Shared => "*const ", | ||
870 | hir_def::type_ref::Mutability::Mut => "*mut ", | ||
871 | }; | ||
872 | write!(f, "{}", mutability)?; | ||
873 | inner.hir_fmt(f)?; | ||
874 | } | ||
875 | TypeRef::Reference(inner, lifetime, mutability) => { | ||
876 | let mutability = match mutability { | ||
877 | hir_def::type_ref::Mutability::Shared => "", | ||
878 | hir_def::type_ref::Mutability::Mut => "mut ", | ||
879 | }; | ||
880 | write!(f, "&")?; | ||
881 | if let Some(lifetime) = lifetime { | ||
882 | write!(f, "{} ", lifetime.name)?; | ||
883 | } | ||
884 | write!(f, "{}", mutability)?; | ||
885 | inner.hir_fmt(f)?; | ||
886 | } | ||
887 | TypeRef::Array(inner) => { | ||
888 | write!(f, "[")?; | ||
889 | inner.hir_fmt(f)?; | ||
890 | // FIXME: Array length? | ||
891 | write!(f, "; _]")?; | ||
892 | } | ||
893 | TypeRef::Slice(inner) => { | ||
894 | write!(f, "[")?; | ||
895 | inner.hir_fmt(f)?; | ||
896 | write!(f, "]")?; | ||
897 | } | ||
898 | TypeRef::Fn(tys, is_varargs) => { | ||
899 | // FIXME: Function pointer qualifiers. | ||
900 | write!(f, "fn(")?; | ||
901 | f.write_joined(&tys[..tys.len() - 1], ", ")?; | ||
902 | if *is_varargs { | ||
903 | write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?; | ||
904 | } | ||
905 | write!(f, ")")?; | ||
906 | let ret_ty = tys.last().unwrap(); | ||
907 | match ret_ty { | ||
908 | TypeRef::Tuple(tup) if tup.is_empty() => {} | ||
909 | _ => { | ||
910 | write!(f, " -> ")?; | ||
911 | ret_ty.hir_fmt(f)?; | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | TypeRef::ImplTrait(bounds) => { | ||
916 | write!(f, "impl ")?; | ||
917 | f.write_joined(bounds, " + ")?; | ||
918 | } | ||
919 | TypeRef::DynTrait(bounds) => { | ||
920 | write!(f, "dyn ")?; | ||
921 | f.write_joined(bounds, " + ")?; | ||
922 | } | ||
923 | TypeRef::Error => write!(f, "{{error}}")?, | ||
924 | } | ||
925 | Ok(()) | ||
926 | } | ||
927 | } | ||
928 | |||
929 | impl HirDisplay for TypeBound { | ||
930 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
931 | match self { | ||
932 | TypeBound::Path(path) => path.hir_fmt(f), | ||
933 | TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name), | ||
934 | TypeBound::Error => write!(f, "{{error}}"), | ||
935 | } | ||
936 | } | ||
937 | } | ||
938 | |||
939 | impl HirDisplay for Path { | ||
940 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
941 | match (self.type_anchor(), self.kind()) { | ||
942 | (Some(anchor), _) => { | ||
943 | write!(f, "<")?; | ||
944 | anchor.hir_fmt(f)?; | ||
945 | write!(f, ">")?; | ||
946 | } | ||
947 | (_, PathKind::Plain) => {} | ||
948 | (_, PathKind::Abs) => write!(f, "::")?, | ||
949 | (_, PathKind::Crate) => write!(f, "crate")?, | ||
950 | (_, PathKind::Super(0)) => write!(f, "self")?, | ||
951 | (_, PathKind::Super(n)) => { | ||
952 | write!(f, "super")?; | ||
953 | for _ in 0..*n { | ||
954 | write!(f, "::super")?; | ||
955 | } | ||
956 | } | ||
957 | (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?, | ||
958 | } | ||
959 | |||
960 | for (seg_idx, segment) in self.segments().iter().enumerate() { | ||
961 | if seg_idx != 0 { | ||
962 | write!(f, "::")?; | ||
963 | } | ||
964 | write!(f, "{}", segment.name)?; | ||
965 | if let Some(generic_args) = segment.args_and_bindings { | ||
966 | // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`. | ||
967 | // Do we actually format expressions? | ||
968 | write!(f, "<")?; | ||
969 | let mut first = true; | ||
970 | for arg in &generic_args.args { | ||
971 | if first { | ||
972 | first = false; | ||
973 | if generic_args.has_self_type { | ||
974 | // FIXME: Convert to `<Ty as Trait>` form. | ||
975 | write!(f, "Self = ")?; | ||
976 | } | ||
977 | } else { | ||
978 | write!(f, ", ")?; | ||
979 | } | ||
980 | arg.hir_fmt(f)?; | ||
981 | } | ||
982 | for binding in &generic_args.bindings { | ||
983 | if first { | ||
984 | first = false; | ||
985 | } else { | ||
986 | write!(f, ", ")?; | ||
987 | } | ||
988 | write!(f, "{}", binding.name)?; | ||
989 | match &binding.type_ref { | ||
990 | Some(ty) => { | ||
991 | write!(f, " = ")?; | ||
992 | ty.hir_fmt(f)? | ||
993 | } | ||
994 | None => { | ||
995 | write!(f, ": ")?; | ||
996 | f.write_joined(&binding.bounds, " + ")?; | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | write!(f, ">")?; | ||
1001 | } | ||
1002 | } | ||
1003 | Ok(()) | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | impl HirDisplay for GenericArg { | ||
1008 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1009 | match self { | ||
1010 | GenericArg::Type(ty) => ty.hir_fmt(f), | ||
1011 | GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name), | ||
1012 | } | ||
1013 | } | ||
1014 | } | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index f872b68cf..1e4c247c0 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -354,7 +354,7 @@ fn hover_for_definition( | |||
354 | }, | 354 | }, |
355 | mod_path, | 355 | mod_path, |
356 | ), | 356 | ), |
357 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), | 357 | ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path), |
358 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), | 358 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), |
359 | ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), | 359 | ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), |
360 | ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), | 360 | ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path), |
@@ -383,6 +383,14 @@ fn hover_for_definition( | |||
383 | }, | 383 | }, |
384 | }; | 384 | }; |
385 | 385 | ||
386 | fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | ||
387 | where | ||
388 | D: HasAttrs + HirDisplay, | ||
389 | { | ||
390 | let label = def.display(db).to_string(); | ||
391 | from_def_source_labeled(db, def, Some(label), mod_path) | ||
392 | } | ||
393 | |||
386 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 394 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
387 | where | 395 | where |
388 | D: HasSource<Ast = A> + HasAttrs + Copy, | 396 | D: HasSource<Ast = A> + HasAttrs + Copy, |