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