]>
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 | |
fc512014 | 24 | // or an omission (FIXME). |
041b39d2 XL |
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 | |
3dfed10e | 32 | use rustc_ast::Mutability; |
f035d41b | 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. | |
6a06907d | 58 | pub fn field_signature(field: &hir::FieldDef<'_>, 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(); | |
29967ef6 | 265 | // FIXME should put the proper path in there, not ellipsis. |
041b39d2 XL |
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)?; | |
29967ef6 | 275 | let prefix = format!("<{}>::", nested_ty.text); |
f035d41b XL |
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 | } |
3dfed10e XL |
289 | hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { |
290 | Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name()))) | |
291 | } | |
f035d41b | 292 | hir::TyKind::TraitObject(bounds, ..) => { |
041b39d2 | 293 | // FIXME recurse into bounds |
f035d41b XL |
294 | let bounds: Vec<hir::GenericBound<'_>> = bounds |
295 | .iter() | |
296 | .map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| { | |
297 | hir::GenericBound::Trait( | |
298 | hir::PolyTraitRef { | |
299 | bound_generic_params, | |
300 | trait_ref: hir::TraitRef { | |
301 | path: trait_ref.path, | |
302 | hir_ref_id: trait_ref.hir_ref_id, | |
303 | }, | |
304 | span: *span, | |
305 | }, | |
306 | hir::TraitBoundModifier::None, | |
307 | ) | |
308 | }) | |
309 | .collect(); | |
310 | let nested = bounds_to_string(&bounds); | |
311 | Ok(text_sig(nested)) | |
041b39d2 | 312 | } |
f035d41b | 313 | hir::TyKind::Array(ref ty, ref anon_const) => { |
041b39d2 | 314 | let nested_ty = ty.make(offset + 1, id, scx)?; |
f035d41b | 315 | let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); |
041b39d2 XL |
316 | let text = format!("[{}; {}]", nested_ty.text, expr); |
317 | Ok(replace_text(nested_ty, text)) | |
318 | } | |
f035d41b | 319 | hir::TyKind::OpaqueDef(item_id, _) => { |
6a06907d XL |
320 | let item = scx.tcx.hir().item(item_id); |
321 | item.make(offset, Some(item_id.hir_id()), scx) | |
f035d41b XL |
322 | } |
323 | hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"), | |
041b39d2 XL |
324 | } |
325 | } | |
326 | } | |
327 | ||
f035d41b XL |
328 | impl<'hir> Sig for hir::Item<'hir> { |
329 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
6a06907d | 330 | let id = Some(self.hir_id()); |
041b39d2 | 331 | |
e74abb32 | 332 | match self.kind { |
f035d41b | 333 | hir::ItemKind::Static(ref ty, m, ref body) => { |
041b39d2 | 334 | let mut text = "static ".to_owned(); |
f035d41b | 335 | if m == hir::Mutability::Mut { |
041b39d2 XL |
336 | text.push_str("mut "); |
337 | } | |
338 | let name = self.ident.to_string(); | |
dfeec247 | 339 | let defs = vec![SigElement { |
6a06907d | 340 | id: id_from_def_id(self.def_id.to_def_id()), |
dfeec247 XL |
341 | start: offset + text.len(), |
342 | end: offset + text.len() + name.len(), | |
343 | }]; | |
041b39d2 XL |
344 | text.push_str(&name); |
345 | text.push_str(": "); | |
346 | ||
347 | let ty = ty.make(offset + text.len(), id, scx)?; | |
348 | text.push_str(&ty.text); | |
041b39d2 | 349 | |
f035d41b XL |
350 | text.push_str(" = "); |
351 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); | |
352 | text.push_str(&expr); | |
74b04a01 | 353 | |
041b39d2 XL |
354 | text.push(';'); |
355 | ||
356 | Ok(extend_sig(ty, text, defs, vec![])) | |
357 | } | |
f035d41b | 358 | hir::ItemKind::Const(ref ty, ref body) => { |
041b39d2 XL |
359 | let mut text = "const ".to_owned(); |
360 | let name = self.ident.to_string(); | |
dfeec247 | 361 | let defs = vec![SigElement { |
6a06907d | 362 | id: id_from_def_id(self.def_id.to_def_id()), |
dfeec247 XL |
363 | start: offset + text.len(), |
364 | end: offset + text.len() + name.len(), | |
365 | }]; | |
041b39d2 XL |
366 | text.push_str(&name); |
367 | text.push_str(": "); | |
368 | ||
369 | let ty = ty.make(offset + text.len(), id, scx)?; | |
370 | text.push_str(&ty.text); | |
041b39d2 | 371 | |
f035d41b XL |
372 | text.push_str(" = "); |
373 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); | |
374 | text.push_str(&expr); | |
74b04a01 | 375 | |
041b39d2 XL |
376 | text.push(';'); |
377 | ||
378 | Ok(extend_sig(ty, text, defs, vec![])) | |
379 | } | |
3dfed10e | 380 | hir::ItemKind::Fn(hir::FnSig { ref decl, header, span: _ }, ref generics, _) => { |
041b39d2 | 381 | let mut text = String::new(); |
f035d41b | 382 | if let hir::Constness::Const = header.constness { |
041b39d2 XL |
383 | text.push_str("const "); |
384 | } | |
f035d41b | 385 | if hir::IsAsync::Async == header.asyncness { |
8faf50e0 XL |
386 | text.push_str("async "); |
387 | } | |
f035d41b | 388 | if let hir::Unsafety::Unsafe = header.unsafety { |
041b39d2 XL |
389 | text.push_str("unsafe "); |
390 | } | |
041b39d2 XL |
391 | text.push_str("fn "); |
392 | ||
f035d41b | 393 | let mut sig = |
6a06907d | 394 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
395 | |
396 | sig.text.push('('); | |
f035d41b | 397 | for i in decl.inputs { |
3b2f2976 | 398 | // FIXME should descend into patterns to add defs. |
041b39d2 | 399 | sig.text.push_str(": "); |
f035d41b | 400 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
401 | sig.text.push_str(&nested.text); |
402 | sig.text.push(','); | |
403 | sig.defs.extend(nested.defs.into_iter()); | |
404 | sig.refs.extend(nested.refs.into_iter()); | |
405 | } | |
406 | sig.text.push(')'); | |
407 | ||
f035d41b | 408 | if let hir::FnRetTy::Return(ref t) = decl.output { |
041b39d2 XL |
409 | sig.text.push_str(" -> "); |
410 | let nested = t.make(offset + sig.text.len(), None, scx)?; | |
411 | sig.text.push_str(&nested.text); | |
412 | sig.defs.extend(nested.defs.into_iter()); | |
413 | sig.refs.extend(nested.refs.into_iter()); | |
414 | } | |
415 | sig.text.push_str(" {}"); | |
416 | ||
417 | Ok(sig) | |
418 | } | |
f035d41b | 419 | hir::ItemKind::Mod(ref _mod) => { |
041b39d2 XL |
420 | let mut text = "mod ".to_owned(); |
421 | let name = self.ident.to_string(); | |
dfeec247 | 422 | let defs = vec![SigElement { |
6a06907d | 423 | id: id_from_def_id(self.def_id.to_def_id()), |
dfeec247 XL |
424 | start: offset + text.len(), |
425 | end: offset + text.len() + name.len(), | |
426 | }]; | |
041b39d2 | 427 | text.push_str(&name); |
b7449926 | 428 | // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one. |
041b39d2 XL |
429 | text.push(';'); |
430 | ||
dfeec247 | 431 | Ok(Signature { text, defs, refs: vec![] }) |
041b39d2 | 432 | } |
f035d41b | 433 | hir::ItemKind::TyAlias(ref ty, ref generics) => { |
416331ca | 434 | let text = "type ".to_owned(); |
f035d41b | 435 | let mut sig = |
6a06907d | 436 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
8faf50e0 | 437 | |
416331ca | 438 | sig.text.push_str(" = "); |
f035d41b | 439 | let ty = ty.make(offset + sig.text.len(), id, scx)?; |
416331ca | 440 | sig.text.push_str(&ty.text); |
8faf50e0 XL |
441 | sig.text.push(';'); |
442 | ||
416331ca | 443 | Ok(merge_sigs(sig.text.clone(), vec![sig, ty])) |
8faf50e0 | 444 | } |
f035d41b | 445 | hir::ItemKind::Enum(_, ref generics) => { |
041b39d2 | 446 | let text = "enum ".to_owned(); |
f035d41b | 447 | let mut sig = |
6a06907d | 448 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
449 | sig.text.push_str(" {}"); |
450 | Ok(sig) | |
451 | } | |
f035d41b | 452 | hir::ItemKind::Struct(_, ref generics) => { |
041b39d2 | 453 | let text = "struct ".to_owned(); |
f035d41b | 454 | let mut sig = |
6a06907d | 455 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
456 | sig.text.push_str(" {}"); |
457 | Ok(sig) | |
458 | } | |
f035d41b | 459 | hir::ItemKind::Union(_, ref generics) => { |
041b39d2 | 460 | let text = "union ".to_owned(); |
f035d41b | 461 | let mut sig = |
6a06907d | 462 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
463 | sig.text.push_str(" {}"); |
464 | Ok(sig) | |
465 | } | |
f035d41b | 466 | hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => { |
041b39d2 | 467 | let mut text = String::new(); |
abe05a73 | 468 | |
f035d41b | 469 | if is_auto == hir::IsAuto::Yes { |
abe05a73 XL |
470 | text.push_str("auto "); |
471 | } | |
472 | ||
f035d41b | 473 | if let hir::Unsafety::Unsafe = unsafety { |
041b39d2 XL |
474 | text.push_str("unsafe "); |
475 | } | |
476 | text.push_str("trait "); | |
f035d41b | 477 | let mut sig = |
6a06907d | 478 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
479 | |
480 | if !bounds.is_empty() { | |
481 | sig.text.push_str(": "); | |
f035d41b | 482 | sig.text.push_str(&bounds_to_string(bounds)); |
041b39d2 XL |
483 | } |
484 | // FIXME where clause | |
485 | sig.text.push_str(" {}"); | |
486 | ||
487 | Ok(sig) | |
488 | } | |
f035d41b | 489 | hir::ItemKind::TraitAlias(ref generics, bounds) => { |
ff7c6d11 XL |
490 | let mut text = String::new(); |
491 | text.push_str("trait "); | |
f035d41b | 492 | let mut sig = |
6a06907d | 493 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
ff7c6d11 XL |
494 | |
495 | if !bounds.is_empty() { | |
496 | sig.text.push_str(" = "); | |
f035d41b | 497 | sig.text.push_str(&bounds_to_string(bounds)); |
ff7c6d11 XL |
498 | } |
499 | // FIXME where clause | |
1b1a35ee | 500 | sig.text.push(';'); |
ff7c6d11 XL |
501 | |
502 | Ok(sig) | |
503 | } | |
5869c6ff | 504 | hir::ItemKind::Impl(hir::Impl { |
abe05a73 XL |
505 | unsafety, |
506 | polarity, | |
507 | defaultness, | |
f035d41b | 508 | defaultness_span: _, |
dfeec247 | 509 | constness, |
abe05a73 | 510 | ref generics, |
dfeec247 XL |
511 | ref of_trait, |
512 | ref self_ty, | |
513 | items: _, | |
5869c6ff | 514 | }) => { |
041b39d2 | 515 | let mut text = String::new(); |
f035d41b | 516 | if let hir::Defaultness::Default { .. } = defaultness { |
041b39d2 XL |
517 | text.push_str("default "); |
518 | } | |
f035d41b | 519 | if let hir::Unsafety::Unsafe = unsafety { |
041b39d2 XL |
520 | text.push_str("unsafe "); |
521 | } | |
522 | text.push_str("impl"); | |
f035d41b | 523 | if let hir::Constness::Const = constness { |
dfeec247 XL |
524 | text.push_str(" const"); |
525 | } | |
041b39d2 XL |
526 | |
527 | let generics_sig = generics.make(offset + text.len(), id, scx)?; | |
528 | text.push_str(&generics_sig.text); | |
529 | ||
530 | text.push(' '); | |
531 | ||
dfeec247 | 532 | let trait_sig = if let Some(ref t) = *of_trait { |
f035d41b | 533 | if let hir::ImplPolarity::Negative(_) = polarity { |
041b39d2 XL |
534 | text.push('!'); |
535 | } | |
536 | let trait_sig = t.path.make(offset + text.len(), id, scx)?; | |
537 | text.push_str(&trait_sig.text); | |
538 | text.push_str(" for "); | |
539 | trait_sig | |
540 | } else { | |
541 | text_sig(String::new()) | |
542 | }; | |
543 | ||
dfeec247 | 544 | let ty_sig = self_ty.make(offset + text.len(), id, scx)?; |
041b39d2 XL |
545 | text.push_str(&ty_sig.text); |
546 | ||
547 | text.push_str(" {}"); | |
548 | ||
549 | Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig])) | |
550 | ||
551 | // FIXME where clause | |
552 | } | |
fc512014 | 553 | hir::ItemKind::ForeignMod { .. } => Err("extern mod"), |
29967ef6 | 554 | hir::ItemKind::GlobalAsm(_) => Err("global asm"), |
f035d41b XL |
555 | hir::ItemKind::ExternCrate(_) => Err("extern crate"), |
556 | hir::ItemKind::OpaqueTy(..) => Err("opaque type"), | |
041b39d2 | 557 | // FIXME should implement this (e.g., pub use). |
f035d41b | 558 | hir::ItemKind::Use(..) => Err("import"), |
041b39d2 XL |
559 | } |
560 | } | |
561 | } | |
562 | ||
f035d41b XL |
563 | impl<'hir> Sig for hir::Path<'hir> { |
564 | fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
48663c56 | 565 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
041b39d2 | 566 | |
48663c56 XL |
567 | let (name, start, end) = match res { |
568 | Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { | |
f035d41b | 569 | return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] }); |
041b39d2 | 570 | } |
ba9703b0 | 571 | Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => { |
041b39d2 XL |
572 | let len = self.segments.len(); |
573 | if len < 2 { | |
574 | return Err("Bad path"); | |
575 | } | |
576 | // FIXME: really we should descend into the generics here and add SigElements for | |
577 | // them. | |
578 | // FIXME: would be nice to have a def for the first path segment. | |
f035d41b XL |
579 | let seg1 = path_segment_to_string(&self.segments[len - 2]); |
580 | let seg2 = path_segment_to_string(&self.segments[len - 1]); | |
041b39d2 XL |
581 | let start = offset + seg1.len() + 2; |
582 | (format!("{}::{}", seg1, seg2), start, start + seg2.len()) | |
583 | } | |
584 | _ => { | |
f035d41b | 585 | let name = path_segment_to_string(self.segments.last().ok_or("Bad path")?); |
041b39d2 XL |
586 | let end = offset + name.len(); |
587 | (name, offset, end) | |
588 | } | |
589 | }; | |
590 | ||
48663c56 | 591 | let id = id_from_def_id(res.def_id()); |
dfeec247 | 592 | Ok(Signature { text: name, defs: vec![], refs: vec![SigElement { id, start, end }] }) |
041b39d2 XL |
593 | } |
594 | } | |
595 | ||
596 | // This does not cover the where clause, which must be processed separately. | |
f035d41b XL |
597 | impl<'hir> Sig for hir::Generics<'hir> { |
598 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
ff7c6d11 | 599 | if self.params.is_empty() { |
041b39d2 XL |
600 | return Ok(text_sig(String::new())); |
601 | } | |
602 | ||
603 | let mut text = "<".to_owned(); | |
604 | ||
b7449926 | 605 | let mut defs = Vec::with_capacity(self.params.len()); |
f035d41b | 606 | for param in self.params { |
9fa01778 | 607 | let mut param_text = String::new(); |
f035d41b | 608 | if let hir::GenericParamKind::Const { .. } = param.kind { |
9fa01778 XL |
609 | param_text.push_str("const "); |
610 | } | |
f035d41b | 611 | param_text.push_str(¶m.name.ident().as_str()); |
8faf50e0 | 612 | defs.push(SigElement { |
f035d41b | 613 | id: id_from_hir_id(param.hir_id, scx), |
8faf50e0 | 614 | start: offset + text.len(), |
9fa01778 | 615 | end: offset + text.len() + param_text.as_str().len(), |
8faf50e0 | 616 | }); |
5869c6ff | 617 | if let hir::GenericParamKind::Const { ref ty, ref default } = param.kind { |
9fa01778 | 618 | param_text.push_str(": "); |
f035d41b | 619 | param_text.push_str(&ty_to_string(&ty)); |
5869c6ff XL |
620 | if let Some(ref _default) = default { |
621 | // FIXME(const_generics_defaults): push the `default` value here | |
622 | } | |
9fa01778 | 623 | } |
8faf50e0 XL |
624 | if !param.bounds.is_empty() { |
625 | param_text.push_str(": "); | |
626 | match param.kind { | |
f035d41b | 627 | hir::GenericParamKind::Lifetime { .. } => { |
dfeec247 XL |
628 | let bounds = param |
629 | .bounds | |
630 | .iter() | |
8faf50e0 | 631 | .map(|bound| match bound { |
f035d41b | 632 | hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(), |
8faf50e0 XL |
633 | _ => panic!(), |
634 | }) | |
ff7c6d11 XL |
635 | .collect::<Vec<_>>() |
636 | .join(" + "); | |
8faf50e0 | 637 | param_text.push_str(&bounds); |
ff7c6d11 XL |
638 | // FIXME add lifetime bounds refs. |
639 | } | |
f035d41b XL |
640 | hir::GenericParamKind::Type { .. } => { |
641 | param_text.push_str(&bounds_to_string(param.bounds)); | |
ff7c6d11 XL |
642 | // FIXME descend properly into bounds. |
643 | } | |
f035d41b | 644 | hir::GenericParamKind::Const { .. } => { |
9fa01778 XL |
645 | // Const generics cannot contain bounds. |
646 | } | |
ff7c6d11 | 647 | } |
041b39d2 | 648 | } |
8faf50e0 XL |
649 | text.push_str(¶m_text); |
650 | text.push(','); | |
041b39d2 XL |
651 | } |
652 | ||
653 | text.push('>'); | |
dfeec247 | 654 | Ok(Signature { text, defs, refs: vec![] }) |
041b39d2 XL |
655 | } |
656 | } | |
657 | ||
6a06907d | 658 | impl<'hir> Sig for hir::FieldDef<'hir> { |
f035d41b | 659 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
041b39d2 | 660 | let mut text = String::new(); |
041b39d2 | 661 | |
f035d41b XL |
662 | text.push_str(&self.ident.to_string()); |
663 | let defs = Some(SigElement { | |
664 | id: id_from_hir_id(self.hir_id, scx), | |
665 | start: offset, | |
666 | end: offset + text.len(), | |
667 | }); | |
668 | text.push_str(": "); | |
669 | ||
670 | let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?; | |
041b39d2 XL |
671 | text.push_str(&ty_sig.text); |
672 | ty_sig.text = text; | |
673 | ty_sig.defs.extend(defs.into_iter()); | |
674 | Ok(ty_sig) | |
675 | } | |
676 | } | |
677 | ||
f035d41b XL |
678 | impl<'hir> Sig for hir::Variant<'hir> { |
679 | fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
83c7162d | 680 | let mut text = self.ident.to_string(); |
041b39d2 | 681 | match self.data { |
f035d41b | 682 | hir::VariantData::Struct(fields, r) => { |
fc512014 | 683 | let id = parent_id.ok_or("Missing id for Variant's parent")?; |
041b39d2 | 684 | let name_def = SigElement { |
f035d41b | 685 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
686 | start: offset, |
687 | end: offset + text.len(), | |
688 | }; | |
689 | text.push_str(" { "); | |
690 | let mut defs = vec![name_def]; | |
691 | let mut refs = vec![]; | |
532ac7d7 XL |
692 | if r { |
693 | text.push_str("/* parse error */ "); | |
694 | } else { | |
695 | for f in fields { | |
696 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; | |
697 | text.push_str(&field_sig.text); | |
698 | text.push_str(", "); | |
699 | defs.extend(field_sig.defs.into_iter()); | |
700 | refs.extend(field_sig.refs.into_iter()); | |
701 | } | |
041b39d2 XL |
702 | } |
703 | text.push('}'); | |
abe05a73 | 704 | Ok(Signature { text, defs, refs }) |
041b39d2 | 705 | } |
f035d41b | 706 | hir::VariantData::Tuple(fields, id) => { |
041b39d2 | 707 | let name_def = SigElement { |
f035d41b | 708 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
709 | start: offset, |
710 | end: offset + text.len(), | |
711 | }; | |
712 | text.push('('); | |
713 | let mut defs = vec![name_def]; | |
714 | let mut refs = vec![]; | |
715 | for f in fields { | |
716 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; | |
717 | text.push_str(&field_sig.text); | |
718 | text.push_str(", "); | |
719 | defs.extend(field_sig.defs.into_iter()); | |
720 | refs.extend(field_sig.refs.into_iter()); | |
721 | } | |
722 | text.push(')'); | |
abe05a73 | 723 | Ok(Signature { text, defs, refs }) |
041b39d2 | 724 | } |
f035d41b | 725 | hir::VariantData::Unit(id) => { |
041b39d2 | 726 | let name_def = SigElement { |
f035d41b | 727 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
728 | start: offset, |
729 | end: offset + text.len(), | |
730 | }; | |
dfeec247 | 731 | Ok(Signature { text, defs: vec![name_def], refs: vec![] }) |
041b39d2 XL |
732 | } |
733 | } | |
734 | } | |
735 | } | |
736 | ||
f035d41b XL |
737 | impl<'hir> Sig for hir::ForeignItem<'hir> { |
738 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { | |
6a06907d | 739 | let id = Some(self.hir_id()); |
e74abb32 | 740 | match self.kind { |
f035d41b | 741 | hir::ForeignItemKind::Fn(decl, _, ref generics) => { |
041b39d2 XL |
742 | let mut text = String::new(); |
743 | text.push_str("fn "); | |
744 | ||
f035d41b | 745 | let mut sig = |
6a06907d | 746 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
041b39d2 XL |
747 | |
748 | sig.text.push('('); | |
f035d41b | 749 | for i in decl.inputs { |
041b39d2 | 750 | sig.text.push_str(": "); |
f035d41b | 751 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
752 | sig.text.push_str(&nested.text); |
753 | sig.text.push(','); | |
754 | sig.defs.extend(nested.defs.into_iter()); | |
755 | sig.refs.extend(nested.refs.into_iter()); | |
756 | } | |
757 | sig.text.push(')'); | |
758 | ||
f035d41b | 759 | if let hir::FnRetTy::Return(ref t) = decl.output { |
041b39d2 XL |
760 | sig.text.push_str(" -> "); |
761 | let nested = t.make(offset + sig.text.len(), None, scx)?; | |
762 | sig.text.push_str(&nested.text); | |
763 | sig.defs.extend(nested.defs.into_iter()); | |
764 | sig.refs.extend(nested.refs.into_iter()); | |
765 | } | |
766 | sig.text.push(';'); | |
767 | ||
768 | Ok(sig) | |
769 | } | |
f035d41b | 770 | hir::ForeignItemKind::Static(ref ty, m) => { |
041b39d2 | 771 | let mut text = "static ".to_owned(); |
f035d41b | 772 | if m == Mutability::Mut { |
041b39d2 XL |
773 | text.push_str("mut "); |
774 | } | |
775 | let name = self.ident.to_string(); | |
dfeec247 | 776 | let defs = vec![SigElement { |
6a06907d | 777 | id: id_from_def_id(self.def_id.to_def_id()), |
dfeec247 XL |
778 | start: offset + text.len(), |
779 | end: offset + text.len() + name.len(), | |
780 | }]; | |
041b39d2 XL |
781 | text.push_str(&name); |
782 | text.push_str(": "); | |
783 | ||
784 | let ty_sig = ty.make(offset + text.len(), id, scx)?; | |
785 | text.push(';'); | |
786 | ||
787 | Ok(extend_sig(ty_sig, text, defs, vec![])) | |
788 | } | |
f035d41b | 789 | hir::ForeignItemKind::Type => { |
abe05a73 XL |
790 | let mut text = "type ".to_owned(); |
791 | let name = self.ident.to_string(); | |
dfeec247 | 792 | let defs = vec![SigElement { |
6a06907d | 793 | id: id_from_def_id(self.def_id.to_def_id()), |
dfeec247 XL |
794 | start: offset + text.len(), |
795 | end: offset + text.len() + name.len(), | |
796 | }]; | |
abe05a73 XL |
797 | text.push_str(&name); |
798 | text.push(';'); | |
799 | ||
74b04a01 | 800 | Ok(Signature { text, defs, refs: vec![] }) |
abe05a73 | 801 | } |
041b39d2 XL |
802 | } |
803 | } | |
804 | } | |
805 | ||
abe05a73 XL |
806 | fn name_and_generics( |
807 | mut text: String, | |
808 | offset: usize, | |
f035d41b XL |
809 | generics: &hir::Generics<'_>, |
810 | id: hir::HirId, | |
f9f354fc | 811 | name: Ident, |
f035d41b | 812 | scx: &SaveContext<'_>, |
abe05a73 | 813 | ) -> Result { |
041b39d2 XL |
814 | let name = name.to_string(); |
815 | let def = SigElement { | |
f035d41b | 816 | id: id_from_hir_id(id, scx), |
041b39d2 XL |
817 | start: offset + text.len(), |
818 | end: offset + text.len() + name.len(), | |
819 | }; | |
820 | text.push_str(&name); | |
821 | let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; | |
822 | // FIXME where clause | |
823 | let text = format!("{}{}", text, generics.text); | |
824 | Ok(extend_sig(generics, text, vec![def], vec![])) | |
825 | } | |
826 | ||
abe05a73 | 827 | fn make_assoc_type_signature( |
f035d41b | 828 | id: hir::HirId, |
f9f354fc | 829 | ident: Ident, |
f035d41b XL |
830 | bounds: Option<hir::GenericBounds<'_>>, |
831 | default: Option<&hir::Ty<'_>>, | |
832 | scx: &SaveContext<'_>, | |
abe05a73 | 833 | ) -> Result { |
041b39d2 XL |
834 | let mut text = "type ".to_owned(); |
835 | let name = ident.to_string(); | |
dfeec247 | 836 | let mut defs = vec![SigElement { |
f035d41b | 837 | id: id_from_hir_id(id, scx), |
dfeec247 XL |
838 | start: text.len(), |
839 | end: text.len() + name.len(), | |
840 | }]; | |
041b39d2 XL |
841 | let mut refs = vec![]; |
842 | text.push_str(&name); | |
843 | if let Some(bounds) = bounds { | |
844 | text.push_str(": "); | |
845 | // FIXME should descend into bounds | |
f035d41b | 846 | text.push_str(&bounds_to_string(bounds)); |
041b39d2 XL |
847 | } |
848 | if let Some(default) = default { | |
849 | text.push_str(" = "); | |
850 | let ty_sig = default.make(text.len(), Some(id), scx)?; | |
851 | text.push_str(&ty_sig.text); | |
852 | defs.extend(ty_sig.defs.into_iter()); | |
853 | refs.extend(ty_sig.refs.into_iter()); | |
854 | } | |
855 | text.push(';'); | |
856 | Ok(Signature { text, defs, refs }) | |
857 | } | |
858 | ||
abe05a73 | 859 | fn make_assoc_const_signature( |
f035d41b | 860 | id: hir::HirId, |
f9f354fc | 861 | ident: Symbol, |
f035d41b XL |
862 | ty: &hir::Ty<'_>, |
863 | default: Option<&hir::Expr<'_>>, | |
864 | scx: &SaveContext<'_>, | |
abe05a73 | 865 | ) -> Result { |
041b39d2 XL |
866 | let mut text = "const ".to_owned(); |
867 | let name = ident.to_string(); | |
dfeec247 | 868 | let mut defs = vec![SigElement { |
f035d41b | 869 | id: id_from_hir_id(id, scx), |
dfeec247 XL |
870 | start: text.len(), |
871 | end: text.len() + name.len(), | |
872 | }]; | |
041b39d2 XL |
873 | let mut refs = vec![]; |
874 | text.push_str(&name); | |
875 | text.push_str(": "); | |
876 | ||
877 | let ty_sig = ty.make(text.len(), Some(id), scx)?; | |
878 | text.push_str(&ty_sig.text); | |
879 | defs.extend(ty_sig.defs.into_iter()); | |
880 | refs.extend(ty_sig.refs.into_iter()); | |
881 | ||
882 | if let Some(default) = default { | |
883 | text.push_str(" = "); | |
f035d41b | 884 | text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id)); |
041b39d2 XL |
885 | } |
886 | text.push(';'); | |
887 | Ok(Signature { text, defs, refs }) | |
888 | } | |
889 | ||
abe05a73 | 890 | fn make_method_signature( |
f035d41b | 891 | id: hir::HirId, |
f9f354fc | 892 | ident: Ident, |
f035d41b XL |
893 | generics: &hir::Generics<'_>, |
894 | m: &hir::FnSig<'_>, | |
895 | scx: &SaveContext<'_>, | |
abe05a73 | 896 | ) -> Result { |
041b39d2 XL |
897 | // FIXME code dup with function signature |
898 | let mut text = String::new(); | |
f035d41b | 899 | if let hir::Constness::Const = m.header.constness { |
041b39d2 XL |
900 | text.push_str("const "); |
901 | } | |
f035d41b | 902 | if hir::IsAsync::Async == m.header.asyncness { |
8faf50e0 XL |
903 | text.push_str("async "); |
904 | } | |
f035d41b | 905 | if let hir::Unsafety::Unsafe = m.header.unsafety { |
041b39d2 XL |
906 | text.push_str("unsafe "); |
907 | } | |
041b39d2 XL |
908 | text.push_str("fn "); |
909 | ||
abe05a73 | 910 | let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?; |
041b39d2 XL |
911 | |
912 | sig.text.push('('); | |
f035d41b | 913 | for i in m.decl.inputs { |
041b39d2 | 914 | sig.text.push_str(": "); |
f035d41b | 915 | let nested = i.make(sig.text.len(), Some(i.hir_id), scx)?; |
041b39d2 XL |
916 | sig.text.push_str(&nested.text); |
917 | sig.text.push(','); | |
918 | sig.defs.extend(nested.defs.into_iter()); | |
919 | sig.refs.extend(nested.refs.into_iter()); | |
920 | } | |
921 | sig.text.push(')'); | |
922 | ||
f035d41b | 923 | if let hir::FnRetTy::Return(ref t) = m.decl.output { |
041b39d2 XL |
924 | sig.text.push_str(" -> "); |
925 | let nested = t.make(sig.text.len(), None, scx)?; | |
926 | sig.text.push_str(&nested.text); | |
927 | sig.defs.extend(nested.defs.into_iter()); | |
928 | sig.refs.extend(nested.refs.into_iter()); | |
929 | } | |
930 | sig.text.push_str(" {}"); | |
931 | ||
932 | Ok(sig) | |
933 | } |