]>
Commit | Line | Data |
---|---|---|
041b39d2 XL |
1 | // A signature is a string representation of an item's type signature, excluding |
2 | // any body. It also includes ids for any defs or refs in the signature. For | |
3 | // example: | |
4 | // | |
5 | // ``` | |
6 | // fn foo(x: String) { | |
7 | // println!("{}", x); | |
8 | // } | |
9 | // ``` | |
10 | // The signature string is something like "fn foo(x: String) {}" and the signature | |
11 | // will have defs for `foo` and `x` and a ref for `String`. | |
12 | // | |
13 | // All signature text should parse in the correct context (i.e., in a module or | |
14 | // impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a | |
15 | // signature is not guaranteed to be stable (it may improve or change as the | |
16 | // syntax changes, or whitespace or punctuation may change). It is also likely | |
17 | // not to be pretty - no attempt is made to prettify the text. It is recommended | |
18 | // that clients run the text through Rustfmt. | |
19 | // | |
20 | // This module generates Signatures for items by walking the AST and looking up | |
21 | // references. | |
22 | // | |
23 | // Signatures do not include visibility info. I'm not sure if this is a feature | |
24 | // or an ommission (FIXME). | |
25 | // | |
26 | // FIXME where clauses need implementing, defs/refs in generics are mostly missing. | |
27 | ||
f035d41b | 28 | use crate::{id_from_def_id, id_from_hir_id, SaveContext}; |
041b39d2 | 29 | |
abe05a73 | 30 | use rls_data::{SigElement, Signature}; |
041b39d2 | 31 | |
f035d41b XL |
32 | use rustc_ast::ast::Mutability; |
33 | use rustc_hir as hir; | |
dfeec247 | 34 | use rustc_hir::def::{DefKind, Res}; |
f035d41b XL |
35 | use rustc_hir_pretty::id_to_string; |
36 | use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string}; | |
f9f354fc | 37 | use rustc_span::symbol::{Ident, Symbol}; |
041b39d2 | 38 | |
f035d41b | 39 | pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
3b2f2976 XL |
40 | if !scx.config.signatures { |
41 | return None; | |
42 | } | |
041b39d2 XL |
43 | item.make(0, None, scx).ok() |
44 | } | |
45 | ||
9fa01778 | 46 | pub fn foreign_item_signature( |
f035d41b XL |
47 | item: &hir::ForeignItem<'_>, |
48 | scx: &SaveContext<'_>, | |
9fa01778 | 49 | ) -> Option<Signature> { |
3b2f2976 XL |
50 | if !scx.config.signatures { |
51 | return None; | |
52 | } | |
041b39d2 XL |
53 | item.make(0, None, scx).ok() |
54 | } | |
55 | ||
56 | /// Signature for a struct or tuple field declaration. | |
57 | /// Does not include a trailing comma. | |
f035d41b | 58 | pub fn field_signature(field: &hir::StructField<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
3b2f2976 XL |
59 | if !scx.config.signatures { |
60 | return None; | |
61 | } | |
041b39d2 XL |
62 | field.make(0, None, scx).ok() |
63 | } | |
64 | ||
65 | /// Does not include a trailing comma. | |
f035d41b | 66 | pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
3b2f2976 XL |
67 | if !scx.config.signatures { |
68 | return None; | |
69 | } | |
e1599b0c | 70 | variant.make(0, None, scx).ok() |
041b39d2 XL |
71 | } |
72 | ||
abe05a73 | 73 | pub fn method_signature( |
f035d41b | 74 | id: hir::HirId, |
f9f354fc | 75 | ident: Ident, |
f035d41b XL |
76 | generics: &hir::Generics<'_>, |
77 | m: &hir::FnSig<'_>, | |
78 | scx: &SaveContext<'_>, | |
abe05a73 | 79 | ) -> Option<Signature> { |
3b2f2976 XL |
80 | if !scx.config.signatures { |
81 | return None; | |
82 | } | |
abe05a73 | 83 | make_method_signature(id, ident, generics, m, scx).ok() |
041b39d2 XL |
84 | } |
85 | ||
abe05a73 | 86 | pub fn assoc_const_signature( |
f035d41b | 87 | id: hir::HirId, |
f9f354fc | 88 | ident: Symbol, |
f035d41b XL |
89 | ty: &hir::Ty<'_>, |
90 | default: Option<&hir::Expr<'_>>, | |
91 | scx: &SaveContext<'_>, | |
abe05a73 | 92 | ) -> Option<Signature> { |
3b2f2976 XL |
93 | if !scx.config.signatures { |
94 | return None; | |
95 | } | |
041b39d2 XL |
96 | make_assoc_const_signature(id, ident, ty, default, scx).ok() |
97 | } | |
98 | ||
abe05a73 | 99 | pub fn assoc_type_signature( |
f035d41b | 100 | id: hir::HirId, |
f9f354fc | 101 | ident: Ident, |
f035d41b XL |
102 | bounds: Option<hir::GenericBounds<'_>>, |
103 | default: Option<&hir::Ty<'_>>, | |
104 | scx: &SaveContext<'_>, | |
abe05a73 | 105 | ) -> Option<Signature> { |
3b2f2976 XL |
106 | if !scx.config.signatures { |
107 | return None; | |
108 | } | |
041b39d2 XL |
109 | make_assoc_type_signature(id, ident, bounds, default, scx).ok() |
110 | } | |
111 | ||
9fa01778 | 112 | type Result = std::result::Result<Signature, &'static str>; |
041b39d2 XL |
113 | |
114 | trait Sig { | |
f035d41b | 115 | fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result; |
041b39d2 XL |
116 | } |
117 | ||
abe05a73 XL |
118 | fn extend_sig( |
119 | mut sig: Signature, | |
120 | text: String, | |
121 | defs: Vec<SigElement>, | |
122 | refs: Vec<SigElement>, | |
123 | ) -> Signature { | |
041b39d2 XL |
124 | sig.text = text; |
125 | sig.defs.extend(defs.into_iter()); | |
126 | sig.refs.extend(refs.into_iter()); | |
127 | sig | |
128 | } | |
129 | ||
130 | fn replace_text(mut sig: Signature, text: String) -> Signature { | |
131 | sig.text = text; | |
132 | sig | |
133 | } | |
134 | ||
135 | fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature { | |
dfeec247 | 136 | let mut result = Signature { text, defs: vec![], refs: vec![] }; |
041b39d2 XL |
137 | |
138 | let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip(); | |
139 | ||
dfeec247 XL |
140 | result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter())); |
141 | result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter())); | |
041b39d2 XL |
142 | |
143 | result | |
144 | } | |
145 | ||
146 | fn text_sig(text: String) -> Signature { | |
dfeec247 | 147 | Signature { text, defs: vec![], refs: vec![] } |
041b39d2 XL |
148 | } |
149 | ||
f035d41b XL |
150 | impl<'hir> Sig for hir::Ty<'hir> { |
151 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
152 | let id = Some(self.hir_id); | |
e74abb32 | 153 | match self.kind { |
f035d41b | 154 | hir::TyKind::Slice(ref ty) => { |
041b39d2 XL |
155 | let nested = ty.make(offset + 1, id, scx)?; |
156 | let text = format!("[{}]", nested.text); | |
157 | Ok(replace_text(nested, text)) | |
158 | } | |
f035d41b | 159 | hir::TyKind::Ptr(ref mt) => { |
041b39d2 | 160 | let prefix = match mt.mutbl { |
f035d41b XL |
161 | hir::Mutability::Mut => "*mut ", |
162 | hir::Mutability::Not => "*const ", | |
041b39d2 XL |
163 | }; |
164 | let nested = mt.ty.make(offset + prefix.len(), id, scx)?; | |
165 | let text = format!("{}{}", prefix, nested.text); | |
166 | Ok(replace_text(nested, text)) | |
167 | } | |
f035d41b | 168 | hir::TyKind::Rptr(ref lifetime, ref mt) => { |
041b39d2 | 169 | let mut prefix = "&".to_owned(); |
f035d41b XL |
170 | prefix.push_str(&lifetime.name.ident().to_string()); |
171 | prefix.push(' '); | |
172 | if let hir::Mutability::Mut = mt.mutbl { | |
041b39d2 XL |
173 | prefix.push_str("mut "); |
174 | }; | |
175 | ||
176 | let nested = mt.ty.make(offset + prefix.len(), id, scx)?; | |
177 | let text = format!("{}{}", prefix, nested.text); | |
178 | Ok(replace_text(nested, text)) | |
179 | } | |
f035d41b XL |
180 | hir::TyKind::Never => Ok(text_sig("!".to_owned())), |
181 | hir::TyKind::Tup(ts) => { | |
041b39d2 XL |
182 | let mut text = "(".to_owned(); |
183 | let mut defs = vec![]; | |
184 | let mut refs = vec![]; | |
185 | for t in ts { | |
186 | let nested = t.make(offset + text.len(), id, scx)?; | |
187 | text.push_str(&nested.text); | |
188 | text.push(','); | |
189 | defs.extend(nested.defs.into_iter()); | |
190 | refs.extend(nested.refs.into_iter()); | |
191 | } | |
192 | text.push(')'); | |
193 | Ok(Signature { text, defs, refs }) | |
194 | } | |
f035d41b | 195 | hir::TyKind::BareFn(ref f) => { |
041b39d2 | 196 | let mut text = String::new(); |
ff7c6d11 | 197 | if !f.generic_params.is_empty() { |
041b39d2 XL |
198 | // FIXME defs, bounds on lifetimes |
199 | text.push_str("for<"); | |
dfeec247 XL |
200 | text.push_str( |
201 | &f.generic_params | |
202 | .iter() | |
203 | .filter_map(|param| match param.kind { | |
f035d41b XL |
204 | hir::GenericParamKind::Lifetime { .. } => { |
205 | Some(param.name.ident().to_string()) | |
dfeec247 XL |
206 | } |
207 | _ => None, | |
208 | }) | |
209 | .collect::<Vec<_>>() | |
210 | .join(", "), | |
211 | ); | |
041b39d2 XL |
212 | text.push('>'); |
213 | } | |
214 | ||
f035d41b | 215 | if let hir::Unsafety::Unsafe = f.unsafety { |
041b39d2 XL |
216 | text.push_str("unsafe "); |
217 | } | |
041b39d2 XL |
218 | text.push_str("fn("); |
219 | ||
220 | let mut defs = vec![]; | |
221 | let mut refs = vec![]; | |
f035d41b XL |
222 | for i in f.decl.inputs { |
223 | let nested = i.make(offset + text.len(), Some(i.hir_id), scx)?; | |
041b39d2 XL |
224 | text.push_str(&nested.text); |
225 | text.push(','); | |
226 | defs.extend(nested.defs.into_iter()); | |
227 | refs.extend(nested.refs.into_iter()); | |
228 | } | |
229 | text.push(')'); | |
f035d41b | 230 | if let hir::FnRetTy::Return(ref t) = f.decl.output { |
041b39d2 XL |
231 | text.push_str(" -> "); |
232 | let nested = t.make(offset + text.len(), None, scx)?; | |
233 | text.push_str(&nested.text); | |
234 | text.push(','); | |
235 | defs.extend(nested.defs.into_iter()); | |
236 | refs.extend(nested.refs.into_iter()); | |
237 | } | |
238 | ||
239 | Ok(Signature { text, defs, refs }) | |
240 | } | |
f035d41b XL |
241 | hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.make(offset, id, scx), |
242 | hir::TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref path)) => { | |
243 | let nested_ty = qself.make(offset + 1, id, scx)?; | |
244 | let prefix = format!( | |
245 | "<{} as {}>::", | |
246 | nested_ty.text, | |
247 | path_segment_to_string(&path.segments[0]) | |
248 | ); | |
041b39d2 | 249 | |
f035d41b | 250 | let name = path_segment_to_string(path.segments.last().ok_or("Bad path")?); |
48663c56 XL |
251 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
252 | let id = id_from_def_id(res.def_id()); | |
f035d41b | 253 | if path.segments.len() == 2 { |
041b39d2 XL |
254 | let start = offset + prefix.len(); |
255 | let end = start + name.len(); | |
256 | ||
257 | Ok(Signature { | |
258 | text: prefix + &name, | |
259 | defs: vec![], | |
260 | refs: vec![SigElement { id, start, end }], | |
261 | }) | |
262 | } else { | |
263 | let start = offset + prefix.len() + 5; | |
264 | let end = start + name.len(); | |
265 | // FIXME should put the proper path in there, not elipses. | |
266 | Ok(Signature { | |
267 | text: prefix + "...::" + &name, | |
268 | defs: vec![], | |
269 | refs: vec![SigElement { id, start, end }], | |
270 | }) | |
271 | } | |
272 | } | |
f035d41b XL |
273 | hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { |
274 | let nested_ty = ty.make(offset + 1, id, scx)?; | |
275 | let prefix = format!("<{}>::", nested_ty.text,); | |
276 | ||
277 | let name = path_segment_to_string(segment); | |
278 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); | |
279 | let id = id_from_def_id(res.def_id()); | |
280 | ||
281 | let start = offset + prefix.len(); | |
282 | let end = start + name.len(); | |
283 | Ok(Signature { | |
284 | text: prefix + &name, | |
285 | defs: vec![], | |
286 | refs: vec![SigElement { id, start, end }], | |
287 | }) | |
041b39d2 | 288 | } |
f035d41b | 289 | hir::TyKind::TraitObject(bounds, ..) => { |
041b39d2 | 290 | // FIXME recurse into bounds |
f035d41b XL |
291 | let bounds: Vec<hir::GenericBound<'_>> = bounds |
292 | .iter() | |
293 | .map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| { | |
294 | hir::GenericBound::Trait( | |
295 | hir::PolyTraitRef { | |
296 | bound_generic_params, | |
297 | trait_ref: hir::TraitRef { | |
298 | path: trait_ref.path, | |
299 | hir_ref_id: trait_ref.hir_ref_id, | |
300 | }, | |
301 | span: *span, | |
302 | }, | |
303 | hir::TraitBoundModifier::None, | |
304 | ) | |
305 | }) | |
306 | .collect(); | |
307 | let nested = bounds_to_string(&bounds); | |
308 | Ok(text_sig(nested)) | |
041b39d2 | 309 | } |
f035d41b | 310 | hir::TyKind::Array(ref ty, ref anon_const) => { |
041b39d2 | 311 | let nested_ty = ty.make(offset + 1, id, scx)?; |
f035d41b | 312 | let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); |
041b39d2 XL |
313 | let text = format!("[{}; {}]", nested_ty.text, expr); |
314 | Ok(replace_text(nested_ty, text)) | |
315 | } | |
f035d41b XL |
316 | hir::TyKind::OpaqueDef(item_id, _) => { |
317 | let item = scx.tcx.hir().item(item_id.id); | |
318 | item.make(offset, Some(item_id.id), scx) | |
319 | } | |
320 | hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"), | |
041b39d2 XL |
321 | } |
322 | } | |
323 | } | |
324 | ||
f035d41b XL |
325 | impl<'hir> Sig for hir::Item<'hir> { |
326 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
327 | let id = Some(self.hir_id); | |
041b39d2 | 328 | |
e74abb32 | 329 | match self.kind { |
f035d41b | 330 | hir::ItemKind::Static(ref ty, m, ref body) => { |
041b39d2 | 331 | let mut text = "static ".to_owned(); |
f035d41b | 332 | if m == hir::Mutability::Mut { |
041b39d2 XL |
333 | text.push_str("mut "); |
334 | } | |
335 | let name = self.ident.to_string(); | |
dfeec247 | 336 | let defs = vec![SigElement { |
f035d41b | 337 | id: id_from_hir_id(self.hir_id, scx), |
dfeec247 XL |
338 | start: offset + text.len(), |
339 | end: offset + text.len() + name.len(), | |
340 | }]; | |
041b39d2 XL |
341 | text.push_str(&name); |
342 | text.push_str(": "); | |
343 | ||
344 | let ty = ty.make(offset + text.len(), id, scx)?; | |
345 | text.push_str(&ty.text); | |
041b39d2 | 346 | |
f035d41b XL |
347 | text.push_str(" = "); |
348 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); | |
349 | text.push_str(&expr); | |
74b04a01 | 350 | |
041b39d2 XL |
351 | text.push(';'); |
352 | ||
353 | Ok(extend_sig(ty, text, defs, vec![])) | |
354 | } | |
f035d41b | 355 | hir::ItemKind::Const(ref ty, ref body) => { |
041b39d2 XL |
356 | let mut text = "const ".to_owned(); |
357 | let name = self.ident.to_string(); | |
dfeec247 | 358 | let defs = vec![SigElement { |
f035d41b | 359 | id: id_from_hir_id(self.hir_id, scx), |
dfeec247 XL |
360 | start: offset + text.len(), |
361 | end: offset + text.len() + name.len(), | |
362 | }]; | |
041b39d2 XL |
363 | text.push_str(&name); |
364 | text.push_str(": "); | |
365 | ||
366 | let ty = ty.make(offset + text.len(), id, scx)?; | |
367 | text.push_str(&ty.text); | |
041b39d2 | 368 | |
f035d41b XL |
369 | text.push_str(" = "); |
370 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); | |
371 | text.push_str(&expr); | |
74b04a01 | 372 | |
041b39d2 XL |
373 | text.push(';'); |
374 | ||
375 | Ok(extend_sig(ty, text, defs, vec![])) | |
376 | } | |
f035d41b | 377 | hir::ItemKind::Fn(hir::FnSig { ref decl, header }, ref generics, _) => { |
041b39d2 | 378 | let mut text = String::new(); |
f035d41b | 379 | if let hir::Constness::Const = header.constness { |
041b39d2 XL |
380 | text.push_str("const "); |
381 | } | |
f035d41b | 382 | if hir::IsAsync::Async == header.asyncness { |
8faf50e0 XL |
383 | text.push_str("async "); |
384 | } | |
f035d41b | 385 | if let hir::Unsafety::Unsafe = header.unsafety { |
041b39d2 XL |
386 | text.push_str("unsafe "); |
387 | } | |
041b39d2 XL |
388 | text.push_str("fn "); |
389 | ||
f035d41b XL |
390 | let mut sig = |
391 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
392 | |
393 | sig.text.push('('); | |
f035d41b | 394 | for i in decl.inputs { |
3b2f2976 | 395 | // FIXME should descend into patterns to add defs. |
041b39d2 | 396 | sig.text.push_str(": "); |
f035d41b | 397 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
398 | sig.text.push_str(&nested.text); |
399 | sig.text.push(','); | |
400 | sig.defs.extend(nested.defs.into_iter()); | |
401 | sig.refs.extend(nested.refs.into_iter()); | |
402 | } | |
403 | sig.text.push(')'); | |
404 | ||
f035d41b | 405 | if let hir::FnRetTy::Return(ref t) = decl.output { |
041b39d2 XL |
406 | sig.text.push_str(" -> "); |
407 | let nested = t.make(offset + sig.text.len(), None, scx)?; | |
408 | sig.text.push_str(&nested.text); | |
409 | sig.defs.extend(nested.defs.into_iter()); | |
410 | sig.refs.extend(nested.refs.into_iter()); | |
411 | } | |
412 | sig.text.push_str(" {}"); | |
413 | ||
414 | Ok(sig) | |
415 | } | |
f035d41b | 416 | hir::ItemKind::Mod(ref _mod) => { |
041b39d2 XL |
417 | let mut text = "mod ".to_owned(); |
418 | let name = self.ident.to_string(); | |
dfeec247 | 419 | let defs = vec![SigElement { |
f035d41b | 420 | id: id_from_hir_id(self.hir_id, scx), |
dfeec247 XL |
421 | start: offset + text.len(), |
422 | end: offset + text.len() + name.len(), | |
423 | }]; | |
041b39d2 | 424 | text.push_str(&name); |
b7449926 | 425 | // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one. |
041b39d2 XL |
426 | text.push(';'); |
427 | ||
dfeec247 | 428 | Ok(Signature { text, defs, refs: vec![] }) |
041b39d2 | 429 | } |
f035d41b | 430 | hir::ItemKind::TyAlias(ref ty, ref generics) => { |
416331ca | 431 | let text = "type ".to_owned(); |
f035d41b XL |
432 | let mut sig = |
433 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
8faf50e0 | 434 | |
416331ca | 435 | sig.text.push_str(" = "); |
f035d41b | 436 | let ty = ty.make(offset + sig.text.len(), id, scx)?; |
416331ca | 437 | sig.text.push_str(&ty.text); |
8faf50e0 XL |
438 | sig.text.push(';'); |
439 | ||
416331ca | 440 | Ok(merge_sigs(sig.text.clone(), vec![sig, ty])) |
8faf50e0 | 441 | } |
f035d41b | 442 | hir::ItemKind::Enum(_, ref generics) => { |
041b39d2 | 443 | let text = "enum ".to_owned(); |
f035d41b XL |
444 | let mut sig = |
445 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
446 | sig.text.push_str(" {}"); |
447 | Ok(sig) | |
448 | } | |
f035d41b | 449 | hir::ItemKind::Struct(_, ref generics) => { |
041b39d2 | 450 | let text = "struct ".to_owned(); |
f035d41b XL |
451 | let mut sig = |
452 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
453 | sig.text.push_str(" {}"); |
454 | Ok(sig) | |
455 | } | |
f035d41b | 456 | hir::ItemKind::Union(_, ref generics) => { |
041b39d2 | 457 | let text = "union ".to_owned(); |
f035d41b XL |
458 | let mut sig = |
459 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
460 | sig.text.push_str(" {}"); |
461 | Ok(sig) | |
462 | } | |
f035d41b | 463 | hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => { |
041b39d2 | 464 | let mut text = String::new(); |
abe05a73 | 465 | |
f035d41b | 466 | if is_auto == hir::IsAuto::Yes { |
abe05a73 XL |
467 | text.push_str("auto "); |
468 | } | |
469 | ||
f035d41b | 470 | if let hir::Unsafety::Unsafe = unsafety { |
041b39d2 XL |
471 | text.push_str("unsafe "); |
472 | } | |
473 | text.push_str("trait "); | |
f035d41b XL |
474 | let mut sig = |
475 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
476 | |
477 | if !bounds.is_empty() { | |
478 | sig.text.push_str(": "); | |
f035d41b | 479 | sig.text.push_str(&bounds_to_string(bounds)); |
041b39d2 XL |
480 | } |
481 | // FIXME where clause | |
482 | sig.text.push_str(" {}"); | |
483 | ||
484 | Ok(sig) | |
485 | } | |
f035d41b | 486 | hir::ItemKind::TraitAlias(ref generics, bounds) => { |
ff7c6d11 XL |
487 | let mut text = String::new(); |
488 | text.push_str("trait "); | |
f035d41b XL |
489 | let mut sig = |
490 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
ff7c6d11 XL |
491 | |
492 | if !bounds.is_empty() { | |
493 | sig.text.push_str(" = "); | |
f035d41b | 494 | sig.text.push_str(&bounds_to_string(bounds)); |
ff7c6d11 XL |
495 | } |
496 | // FIXME where clause | |
497 | sig.text.push_str(";"); | |
498 | ||
499 | Ok(sig) | |
500 | } | |
f035d41b | 501 | hir::ItemKind::Impl { |
abe05a73 XL |
502 | unsafety, |
503 | polarity, | |
504 | defaultness, | |
f035d41b | 505 | defaultness_span: _, |
dfeec247 | 506 | constness, |
abe05a73 | 507 | ref generics, |
dfeec247 XL |
508 | ref of_trait, |
509 | ref self_ty, | |
510 | items: _, | |
511 | } => { | |
041b39d2 | 512 | let mut text = String::new(); |
f035d41b | 513 | if let hir::Defaultness::Default { .. } = defaultness { |
041b39d2 XL |
514 | text.push_str("default "); |
515 | } | |
f035d41b | 516 | if let hir::Unsafety::Unsafe = unsafety { |
041b39d2 XL |
517 | text.push_str("unsafe "); |
518 | } | |
519 | text.push_str("impl"); | |
f035d41b | 520 | if let hir::Constness::Const = constness { |
dfeec247 XL |
521 | text.push_str(" const"); |
522 | } | |
041b39d2 XL |
523 | |
524 | let generics_sig = generics.make(offset + text.len(), id, scx)?; | |
525 | text.push_str(&generics_sig.text); | |
526 | ||
527 | text.push(' '); | |
528 | ||
dfeec247 | 529 | let trait_sig = if let Some(ref t) = *of_trait { |
f035d41b | 530 | if let hir::ImplPolarity::Negative(_) = polarity { |
041b39d2 XL |
531 | text.push('!'); |
532 | } | |
533 | let trait_sig = t.path.make(offset + text.len(), id, scx)?; | |
534 | text.push_str(&trait_sig.text); | |
535 | text.push_str(" for "); | |
536 | trait_sig | |
537 | } else { | |
538 | text_sig(String::new()) | |
539 | }; | |
540 | ||
dfeec247 | 541 | let ty_sig = self_ty.make(offset + text.len(), id, scx)?; |
041b39d2 XL |
542 | text.push_str(&ty_sig.text); |
543 | ||
544 | text.push_str(" {}"); | |
545 | ||
546 | Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig])) | |
547 | ||
548 | // FIXME where clause | |
549 | } | |
f035d41b XL |
550 | hir::ItemKind::ForeignMod(_) => Err("extern mod"), |
551 | hir::ItemKind::GlobalAsm(_) => Err("glboal asm"), | |
552 | hir::ItemKind::ExternCrate(_) => Err("extern crate"), | |
553 | hir::ItemKind::OpaqueTy(..) => Err("opaque type"), | |
041b39d2 | 554 | // FIXME should implement this (e.g., pub use). |
f035d41b | 555 | hir::ItemKind::Use(..) => Err("import"), |
041b39d2 XL |
556 | } |
557 | } | |
558 | } | |
559 | ||
f035d41b XL |
560 | impl<'hir> Sig for hir::Path<'hir> { |
561 | fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
48663c56 | 562 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
041b39d2 | 563 | |
48663c56 XL |
564 | let (name, start, end) = match res { |
565 | Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { | |
f035d41b | 566 | return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] }); |
041b39d2 | 567 | } |
ba9703b0 | 568 | Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => { |
041b39d2 XL |
569 | let len = self.segments.len(); |
570 | if len < 2 { | |
571 | return Err("Bad path"); | |
572 | } | |
573 | // FIXME: really we should descend into the generics here and add SigElements for | |
574 | // them. | |
575 | // FIXME: would be nice to have a def for the first path segment. | |
f035d41b XL |
576 | let seg1 = path_segment_to_string(&self.segments[len - 2]); |
577 | let seg2 = path_segment_to_string(&self.segments[len - 1]); | |
041b39d2 XL |
578 | let start = offset + seg1.len() + 2; |
579 | (format!("{}::{}", seg1, seg2), start, start + seg2.len()) | |
580 | } | |
581 | _ => { | |
f035d41b | 582 | let name = path_segment_to_string(self.segments.last().ok_or("Bad path")?); |
041b39d2 XL |
583 | let end = offset + name.len(); |
584 | (name, offset, end) | |
585 | } | |
586 | }; | |
587 | ||
48663c56 | 588 | let id = id_from_def_id(res.def_id()); |
dfeec247 | 589 | Ok(Signature { text: name, defs: vec![], refs: vec![SigElement { id, start, end }] }) |
041b39d2 XL |
590 | } |
591 | } | |
592 | ||
593 | // This does not cover the where clause, which must be processed separately. | |
f035d41b XL |
594 | impl<'hir> Sig for hir::Generics<'hir> { |
595 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
ff7c6d11 | 596 | if self.params.is_empty() { |
041b39d2 XL |
597 | return Ok(text_sig(String::new())); |
598 | } | |
599 | ||
600 | let mut text = "<".to_owned(); | |
601 | ||
b7449926 | 602 | let mut defs = Vec::with_capacity(self.params.len()); |
f035d41b | 603 | for param in self.params { |
9fa01778 | 604 | let mut param_text = String::new(); |
f035d41b | 605 | if let hir::GenericParamKind::Const { .. } = param.kind { |
9fa01778 XL |
606 | param_text.push_str("const "); |
607 | } | |
f035d41b | 608 | param_text.push_str(¶m.name.ident().as_str()); |
8faf50e0 | 609 | defs.push(SigElement { |
f035d41b | 610 | id: id_from_hir_id(param.hir_id, scx), |
8faf50e0 | 611 | start: offset + text.len(), |
9fa01778 | 612 | end: offset + text.len() + param_text.as_str().len(), |
8faf50e0 | 613 | }); |
f035d41b | 614 | if let hir::GenericParamKind::Const { ref ty } = param.kind { |
9fa01778 | 615 | param_text.push_str(": "); |
f035d41b | 616 | param_text.push_str(&ty_to_string(&ty)); |
9fa01778 | 617 | } |
8faf50e0 XL |
618 | if !param.bounds.is_empty() { |
619 | param_text.push_str(": "); | |
620 | match param.kind { | |
f035d41b | 621 | hir::GenericParamKind::Lifetime { .. } => { |
dfeec247 XL |
622 | let bounds = param |
623 | .bounds | |
624 | .iter() | |
8faf50e0 | 625 | .map(|bound| match bound { |
f035d41b | 626 | hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(), |
8faf50e0 XL |
627 | _ => panic!(), |
628 | }) | |
ff7c6d11 XL |
629 | .collect::<Vec<_>>() |
630 | .join(" + "); | |
8faf50e0 | 631 | param_text.push_str(&bounds); |
ff7c6d11 XL |
632 | // FIXME add lifetime bounds refs. |
633 | } | |
f035d41b XL |
634 | hir::GenericParamKind::Type { .. } => { |
635 | param_text.push_str(&bounds_to_string(param.bounds)); | |
ff7c6d11 XL |
636 | // FIXME descend properly into bounds. |
637 | } | |
f035d41b | 638 | hir::GenericParamKind::Const { .. } => { |
9fa01778 XL |
639 | // Const generics cannot contain bounds. |
640 | } | |
ff7c6d11 | 641 | } |
041b39d2 | 642 | } |
8faf50e0 XL |
643 | text.push_str(¶m_text); |
644 | text.push(','); | |
041b39d2 XL |
645 | } |
646 | ||
647 | text.push('>'); | |
dfeec247 | 648 | Ok(Signature { text, defs, refs: vec![] }) |
041b39d2 XL |
649 | } |
650 | } | |
651 | ||
f035d41b XL |
652 | impl<'hir> Sig for hir::StructField<'hir> { |
653 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
041b39d2 | 654 | let mut text = String::new(); |
041b39d2 | 655 | |
f035d41b XL |
656 | text.push_str(&self.ident.to_string()); |
657 | let defs = Some(SigElement { | |
658 | id: id_from_hir_id(self.hir_id, scx), | |
659 | start: offset, | |
660 | end: offset + text.len(), | |
661 | }); | |
662 | text.push_str(": "); | |
663 | ||
664 | let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?; | |
041b39d2 XL |
665 | text.push_str(&ty_sig.text); |
666 | ty_sig.text = text; | |
667 | ty_sig.defs.extend(defs.into_iter()); | |
668 | Ok(ty_sig) | |
669 | } | |
670 | } | |
671 | ||
f035d41b XL |
672 | impl<'hir> Sig for hir::Variant<'hir> { |
673 | fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
83c7162d | 674 | let mut text = self.ident.to_string(); |
041b39d2 | 675 | match self.data { |
f035d41b | 676 | hir::VariantData::Struct(fields, r) => { |
532ac7d7 | 677 | let id = parent_id.unwrap(); |
041b39d2 | 678 | let name_def = SigElement { |
f035d41b | 679 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
680 | start: offset, |
681 | end: offset + text.len(), | |
682 | }; | |
683 | text.push_str(" { "); | |
684 | let mut defs = vec![name_def]; | |
685 | let mut refs = vec![]; | |
532ac7d7 XL |
686 | if r { |
687 | text.push_str("/* parse error */ "); | |
688 | } else { | |
689 | for f in fields { | |
690 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; | |
691 | text.push_str(&field_sig.text); | |
692 | text.push_str(", "); | |
693 | defs.extend(field_sig.defs.into_iter()); | |
694 | refs.extend(field_sig.refs.into_iter()); | |
695 | } | |
041b39d2 XL |
696 | } |
697 | text.push('}'); | |
abe05a73 | 698 | Ok(Signature { text, defs, refs }) |
041b39d2 | 699 | } |
f035d41b | 700 | hir::VariantData::Tuple(fields, id) => { |
041b39d2 | 701 | let name_def = SigElement { |
f035d41b | 702 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
703 | start: offset, |
704 | end: offset + text.len(), | |
705 | }; | |
706 | text.push('('); | |
707 | let mut defs = vec![name_def]; | |
708 | let mut refs = vec![]; | |
709 | for f in fields { | |
710 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; | |
711 | text.push_str(&field_sig.text); | |
712 | text.push_str(", "); | |
713 | defs.extend(field_sig.defs.into_iter()); | |
714 | refs.extend(field_sig.refs.into_iter()); | |
715 | } | |
716 | text.push(')'); | |
abe05a73 | 717 | Ok(Signature { text, defs, refs }) |
041b39d2 | 718 | } |
f035d41b | 719 | hir::VariantData::Unit(id) => { |
041b39d2 | 720 | let name_def = SigElement { |
f035d41b | 721 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
722 | start: offset, |
723 | end: offset + text.len(), | |
724 | }; | |
dfeec247 | 725 | Ok(Signature { text, defs: vec![name_def], refs: vec![] }) |
041b39d2 XL |
726 | } |
727 | } | |
728 | } | |
729 | } | |
730 | ||
f035d41b XL |
731 | impl<'hir> Sig for hir::ForeignItem<'hir> { |
732 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
733 | let id = Some(self.hir_id); | |
e74abb32 | 734 | match self.kind { |
f035d41b | 735 | hir::ForeignItemKind::Fn(decl, _, ref generics) => { |
041b39d2 XL |
736 | let mut text = String::new(); |
737 | text.push_str("fn "); | |
738 | ||
f035d41b XL |
739 | let mut sig = |
740 | name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?; | |
041b39d2 XL |
741 | |
742 | sig.text.push('('); | |
f035d41b | 743 | for i in decl.inputs { |
041b39d2 | 744 | sig.text.push_str(": "); |
f035d41b | 745 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
746 | sig.text.push_str(&nested.text); |
747 | sig.text.push(','); | |
748 | sig.defs.extend(nested.defs.into_iter()); | |
749 | sig.refs.extend(nested.refs.into_iter()); | |
750 | } | |
751 | sig.text.push(')'); | |
752 | ||
f035d41b | 753 | if let hir::FnRetTy::Return(ref t) = decl.output { |
041b39d2 XL |
754 | sig.text.push_str(" -> "); |
755 | let nested = t.make(offset + sig.text.len(), None, scx)?; | |
756 | sig.text.push_str(&nested.text); | |
757 | sig.defs.extend(nested.defs.into_iter()); | |
758 | sig.refs.extend(nested.refs.into_iter()); | |
759 | } | |
760 | sig.text.push(';'); | |
761 | ||
762 | Ok(sig) | |
763 | } | |
f035d41b | 764 | hir::ForeignItemKind::Static(ref ty, m) => { |
041b39d2 | 765 | let mut text = "static ".to_owned(); |
f035d41b | 766 | if m == Mutability::Mut { |
041b39d2 XL |
767 | text.push_str("mut "); |
768 | } | |
769 | let name = self.ident.to_string(); | |
dfeec247 | 770 | let defs = vec![SigElement { |
f035d41b | 771 | id: id_from_hir_id(self.hir_id, scx), |
dfeec247 XL |
772 | start: offset + text.len(), |
773 | end: offset + text.len() + name.len(), | |
774 | }]; | |
041b39d2 XL |
775 | text.push_str(&name); |
776 | text.push_str(": "); | |
777 | ||
778 | let ty_sig = ty.make(offset + text.len(), id, scx)?; | |
779 | text.push(';'); | |
780 | ||
781 | Ok(extend_sig(ty_sig, text, defs, vec![])) | |
782 | } | |
f035d41b | 783 | hir::ForeignItemKind::Type => { |
abe05a73 XL |
784 | let mut text = "type ".to_owned(); |
785 | let name = self.ident.to_string(); | |
dfeec247 | 786 | let defs = vec![SigElement { |
f035d41b | 787 | id: id_from_hir_id(self.hir_id, scx), |
dfeec247 XL |
788 | start: offset + text.len(), |
789 | end: offset + text.len() + name.len(), | |
790 | }]; | |
abe05a73 XL |
791 | text.push_str(&name); |
792 | text.push(';'); | |
793 | ||
74b04a01 | 794 | Ok(Signature { text, defs, refs: vec![] }) |
abe05a73 | 795 | } |
041b39d2 XL |
796 | } |
797 | } | |
798 | } | |
799 | ||
abe05a73 XL |
800 | fn name_and_generics( |
801 | mut text: String, | |
802 | offset: usize, | |
f035d41b XL |
803 | generics: &hir::Generics<'_>, |
804 | id: hir::HirId, | |
f9f354fc | 805 | name: Ident, |
f035d41b | 806 | scx: &SaveContext<'_>, |
abe05a73 | 807 | ) -> Result { |
041b39d2 XL |
808 | let name = name.to_string(); |
809 | let def = SigElement { | |
f035d41b | 810 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
811 | start: offset + text.len(), |
812 | end: offset + text.len() + name.len(), | |
813 | }; | |
814 | text.push_str(&name); | |
815 | let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; | |
816 | // FIXME where clause | |
817 | let text = format!("{}{}", text, generics.text); | |
818 | Ok(extend_sig(generics, text, vec![def], vec![])) | |
819 | } | |
820 | ||
abe05a73 | 821 | fn make_assoc_type_signature( |
f035d41b | 822 | id: hir::HirId, |
f9f354fc | 823 | ident: Ident, |
f035d41b XL |
824 | bounds: Option<hir::GenericBounds<'_>>, |
825 | default: Option<&hir::Ty<'_>>, | |
826 | scx: &SaveContext<'_>, | |
abe05a73 | 827 | ) -> Result { |
041b39d2 XL |
828 | let mut text = "type ".to_owned(); |
829 | let name = ident.to_string(); | |
dfeec247 | 830 | let mut defs = vec![SigElement { |
f035d41b | 831 | id: id_from_hir_id(id, scx), |
dfeec247 XL |
832 | start: text.len(), |
833 | end: text.len() + name.len(), | |
834 | }]; | |
041b39d2 XL |
835 | let mut refs = vec![]; |
836 | text.push_str(&name); | |
837 | if let Some(bounds) = bounds { | |
838 | text.push_str(": "); | |
839 | // FIXME should descend into bounds | |
f035d41b | 840 | text.push_str(&bounds_to_string(bounds)); |
041b39d2 XL |
841 | } |
842 | if let Some(default) = default { | |
843 | text.push_str(" = "); | |
844 | let ty_sig = default.make(text.len(), Some(id), scx)?; | |
845 | text.push_str(&ty_sig.text); | |
846 | defs.extend(ty_sig.defs.into_iter()); | |
847 | refs.extend(ty_sig.refs.into_iter()); | |
848 | } | |
849 | text.push(';'); | |
850 | Ok(Signature { text, defs, refs }) | |
851 | } | |
852 | ||
abe05a73 | 853 | fn make_assoc_const_signature( |
f035d41b | 854 | id: hir::HirId, |
f9f354fc | 855 | ident: Symbol, |
f035d41b XL |
856 | ty: &hir::Ty<'_>, |
857 | default: Option<&hir::Expr<'_>>, | |
858 | scx: &SaveContext<'_>, | |
abe05a73 | 859 | ) -> Result { |
041b39d2 XL |
860 | let mut text = "const ".to_owned(); |
861 | let name = ident.to_string(); | |
dfeec247 | 862 | let mut defs = vec![SigElement { |
f035d41b | 863 | id: id_from_hir_id(id, scx), |
dfeec247 XL |
864 | start: text.len(), |
865 | end: text.len() + name.len(), | |
866 | }]; | |
041b39d2 XL |
867 | let mut refs = vec![]; |
868 | text.push_str(&name); | |
869 | text.push_str(": "); | |
870 | ||
871 | let ty_sig = ty.make(text.len(), Some(id), scx)?; | |
872 | text.push_str(&ty_sig.text); | |
873 | defs.extend(ty_sig.defs.into_iter()); | |
874 | refs.extend(ty_sig.refs.into_iter()); | |
875 | ||
876 | if let Some(default) = default { | |
877 | text.push_str(" = "); | |
f035d41b | 878 | text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id)); |
041b39d2 XL |
879 | } |
880 | text.push(';'); | |
881 | Ok(Signature { text, defs, refs }) | |
882 | } | |
883 | ||
abe05a73 | 884 | fn make_method_signature( |
f035d41b | 885 | id: hir::HirId, |
f9f354fc | 886 | ident: Ident, |
f035d41b XL |
887 | generics: &hir::Generics<'_>, |
888 | m: &hir::FnSig<'_>, | |
889 | scx: &SaveContext<'_>, | |
abe05a73 | 890 | ) -> Result { |
041b39d2 XL |
891 | // FIXME code dup with function signature |
892 | let mut text = String::new(); | |
f035d41b | 893 | if let hir::Constness::Const = m.header.constness { |
041b39d2 XL |
894 | text.push_str("const "); |
895 | } | |
f035d41b | 896 | if hir::IsAsync::Async == m.header.asyncness { |
8faf50e0 XL |
897 | text.push_str("async "); |
898 | } | |
f035d41b | 899 | if let hir::Unsafety::Unsafe = m.header.unsafety { |
041b39d2 XL |
900 | text.push_str("unsafe "); |
901 | } | |
041b39d2 XL |
902 | text.push_str("fn "); |
903 | ||
abe05a73 | 904 | let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?; |
041b39d2 XL |
905 | |
906 | sig.text.push('('); | |
f035d41b | 907 | for i in m.decl.inputs { |
041b39d2 | 908 | sig.text.push_str(": "); |
f035d41b | 909 | let nested = i.make(sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
910 | sig.text.push_str(&nested.text); |
911 | sig.text.push(','); | |
912 | sig.defs.extend(nested.defs.into_iter()); | |
913 | sig.refs.extend(nested.refs.into_iter()); | |
914 | } | |
915 | sig.text.push(')'); | |
916 | ||
f035d41b | 917 | if let hir::FnRetTy::Return(ref t) = m.decl.output { |
041b39d2 XL |
918 | sig.text.push_str(" -> "); |
919 | let nested = t.make(sig.text.len(), None, scx)?; | |
920 | sig.text.push_str(&nested.text); | |
921 | sig.defs.extend(nested.defs.into_iter()); | |
922 | sig.refs.extend(nested.refs.into_iter()); | |
923 | } | |
924 | sig.text.push_str(" {}"); | |
925 | ||
926 | Ok(sig) | |
927 | } |