]> git.proxmox.com Git - rustc.git/blame - src/librustc_save_analysis/sig.rs
New upstream version 1.46.0+dfsg1
[rustc.git] / src / librustc_save_analysis / sig.rs
CommitLineData
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 28use crate::{id_from_def_id, id_from_hir_id, SaveContext};
041b39d2 29
abe05a73 30use rls_data::{SigElement, Signature};
041b39d2 31
f035d41b
XL
32use rustc_ast::ast::Mutability;
33use rustc_hir as hir;
dfeec247 34use rustc_hir::def::{DefKind, Res};
f035d41b
XL
35use rustc_hir_pretty::id_to_string;
36use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string};
f9f354fc 37use rustc_span::symbol::{Ident, Symbol};
041b39d2 38
f035d41b 39pub 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 46pub 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 58pub 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 66pub 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 73pub 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 86pub 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 99pub 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 112type Result = std::result::Result<Signature, &'static str>;
041b39d2
XL
113
114trait Sig {
f035d41b 115 fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result;
041b39d2
XL
116}
117
abe05a73
XL
118fn 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
130fn replace_text(mut sig: Signature, text: String) -> Signature {
131 sig.text = text;
132 sig
133}
134
135fn 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
146fn text_sig(text: String) -> Signature {
dfeec247 147 Signature { text, defs: vec![], refs: vec![] }
041b39d2
XL
148}
149
f035d41b
XL
150impl<'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
325impl<'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
560impl<'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
594impl<'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(&param.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(&param_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
652impl<'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
672impl<'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
731impl<'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
800fn 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 821fn 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 853fn 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 884fn 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}