aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authoroxalica <[email protected]>2021-03-14 12:03:39 +0000
committeroxalica <[email protected]>2021-03-15 17:04:20 +0000
commitef416e0154767619fcbfa0d1682b28bd338a8ce9 (patch)
treee73269dbb569f176e9bba1b16eb74731d63c94c2 /crates
parent2bb8956a102cb2efbea35e414a8214fba2efcaf6 (diff)
Impl HirDisplay for function hover message
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/display.rs234
-rw-r--r--crates/hir/src/lib.rs17
-rw-r--r--crates/hir_def/src/path.rs11
-rw-r--r--crates/hir_ty/src/display.rs203
-rw-r--r--crates/ide/src/hover.rs10
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.
2use hir_def::{
3 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
4 type_ref::{TypeBound, TypeRef},
5 GenericDefId,
6};
2use hir_ty::display::{ 7use 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};
11use syntax::ast::{self, NameOwner};
12
13use crate::{Function, HasVisibility, Substs, Type, TypeParam};
14
15impl 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
6use 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
8impl HirDisplay for Type { 119impl 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
138fn 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
181fn 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 &params.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(&params.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)]
895pub struct Param { 896pub 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
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{hygiene::Hygiene, name::Name}; 12use hir_expand::{
13 hygiene::Hygiene,
14 name::{name, Name},
15};
13use syntax::ast; 16use syntax::ast;
14 17
15use crate::{ 18use 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};
5use arrayvec::ArrayVec; 5use arrayvec::ArrayVec;
6use chalk_ir::Mutability; 6use chalk_ir::Mutability;
7use hir_def::{ 7use 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};
11use hir_expand::name::Name; 17use hir_expand::name::Name;
@@ -232,7 +238,7 @@ where
232 238
233const TYPE_HINT_TRUNCATION: &str = "…"; 239const TYPE_HINT_TRUNCATION: &str = "…";
234 240
235impl HirDisplay for &Ty { 241impl<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
764impl HirDisplay for &GenericPredicate {
765 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
766 HirDisplay::hir_fmt(*self, f)
767 }
768}
769
770impl HirDisplay for GenericPredicate { 770impl 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
829pub 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
853impl 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
929impl 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
939impl 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
1007impl 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,