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
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`.
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.
20 // This module generates Signatures for items by walking the AST and looking up
23 // Signatures do not include visibility info. I'm not sure if this is a feature
24 // or an ommission (FIXME).
26 // FIXME where clauses need implementing, defs/refs in generics are mostly missing.
28 use crate::{id_from_def_id, id_from_node_id, SaveContext};
30 use rls_data::{SigElement, Signature};
32 use rustc_ast_pretty::pprust;
33 use rustc_hir::def::{DefKind, Res};
34 use syntax::ast::{self, Extern, NodeId};
36 pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option<Signature> {
37 if !scx.config.signatures {
40 item.make(0, None, scx).ok()
43 pub fn foreign_item_signature(
44 item: &ast::ForeignItem,
45 scx: &SaveContext<'_, '_>,
46 ) -> Option<Signature> {
47 if !scx.config.signatures {
50 item.make(0, None, scx).ok()
53 /// Signature for a struct or tuple field declaration.
54 /// Does not include a trailing comma.
55 pub fn field_signature(field: &ast::StructField, scx: &SaveContext<'_, '_>) -> Option<Signature> {
56 if !scx.config.signatures {
59 field.make(0, None, scx).ok()
62 /// Does not include a trailing comma.
63 pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext<'_, '_>) -> Option<Signature> {
64 if !scx.config.signatures {
67 variant.make(0, None, scx).ok()
70 pub fn method_signature(
73 generics: &ast::Generics,
75 scx: &SaveContext<'_, '_>,
76 ) -> Option<Signature> {
77 if !scx.config.signatures {
80 make_method_signature(id, ident, generics, m, scx).ok()
83 pub fn assoc_const_signature(
87 default: Option<&ast::Expr>,
88 scx: &SaveContext<'_, '_>,
89 ) -> Option<Signature> {
90 if !scx.config.signatures {
93 make_assoc_const_signature(id, ident, ty, default, scx).ok()
96 pub fn assoc_type_signature(
99 bounds: Option<&ast::GenericBounds>,
100 default: Option<&ast::Ty>,
101 scx: &SaveContext<'_, '_>,
102 ) -> Option<Signature> {
103 if !scx.config.signatures {
106 make_assoc_type_signature(id, ident, bounds, default, scx).ok()
109 type Result = std::result::Result<Signature, &'static str>;
112 fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result;
118 defs: Vec<SigElement>,
119 refs: Vec<SigElement>,
122 sig.defs.extend(defs.into_iter());
123 sig.refs.extend(refs.into_iter());
127 fn replace_text(mut sig: Signature, text: String) -> Signature {
132 fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature {
133 let mut result = Signature { text, defs: vec![], refs: vec![] };
135 let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip();
137 result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter()));
138 result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter()));
143 fn text_sig(text: String) -> Signature {
144 Signature { text, defs: vec![], refs: vec![] }
147 fn push_extern(text: &mut String, ext: Extern) {
150 Extern::Implicit => text.push_str("extern "),
151 Extern::Explicit(abi) => text.push_str(&format!("extern \"{}\" ", abi.symbol)),
155 impl Sig for ast::Ty {
156 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
157 let id = Some(self.id);
159 ast::TyKind::Slice(ref ty) => {
160 let nested = ty.make(offset + 1, id, scx)?;
161 let text = format!("[{}]", nested.text);
162 Ok(replace_text(nested, text))
164 ast::TyKind::Ptr(ref mt) => {
165 let prefix = match mt.mutbl {
166 ast::Mutability::Mut => "*mut ",
167 ast::Mutability::Not => "*const ",
169 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
170 let text = format!("{}{}", prefix, nested.text);
171 Ok(replace_text(nested, text))
173 ast::TyKind::Rptr(ref lifetime, ref mt) => {
174 let mut prefix = "&".to_owned();
175 if let &Some(ref l) = lifetime {
176 prefix.push_str(&l.ident.to_string());
179 if let ast::Mutability::Mut = mt.mutbl {
180 prefix.push_str("mut ");
183 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
184 let text = format!("{}{}", prefix, nested.text);
185 Ok(replace_text(nested, text))
187 ast::TyKind::Never => Ok(text_sig("!".to_owned())),
188 ast::TyKind::CVarArgs => Ok(text_sig("...".to_owned())),
189 ast::TyKind::Tup(ref ts) => {
190 let mut text = "(".to_owned();
191 let mut defs = vec![];
192 let mut refs = vec![];
194 let nested = t.make(offset + text.len(), id, scx)?;
195 text.push_str(&nested.text);
197 defs.extend(nested.defs.into_iter());
198 refs.extend(nested.refs.into_iter());
201 Ok(Signature { text, defs, refs })
203 ast::TyKind::Paren(ref ty) => {
204 let nested = ty.make(offset + 1, id, scx)?;
205 let text = format!("({})", nested.text);
206 Ok(replace_text(nested, text))
208 ast::TyKind::BareFn(ref f) => {
209 let mut text = String::new();
210 if !f.generic_params.is_empty() {
211 // FIXME defs, bounds on lifetimes
212 text.push_str("for<");
216 .filter_map(|param| match param.kind {
217 ast::GenericParamKind::Lifetime { .. } => {
218 Some(param.ident.to_string())
228 if let ast::Unsafe::Yes(_) = f.unsafety {
229 text.push_str("unsafe ");
231 push_extern(&mut text, f.ext);
232 text.push_str("fn(");
234 let mut defs = vec![];
235 let mut refs = vec![];
236 for i in &f.decl.inputs {
237 let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?;
238 text.push_str(&nested.text);
240 defs.extend(nested.defs.into_iter());
241 refs.extend(nested.refs.into_iter());
244 if let ast::FunctionRetTy::Ty(ref t) = f.decl.output {
245 text.push_str(" -> ");
246 let nested = t.make(offset + text.len(), None, scx)?;
247 text.push_str(&nested.text);
249 defs.extend(nested.defs.into_iter());
250 refs.extend(nested.refs.into_iter());
253 Ok(Signature { text, defs, refs })
255 ast::TyKind::Path(None, ref path) => path.make(offset, id, scx),
256 ast::TyKind::Path(Some(ref qself), ref path) => {
257 let nested_ty = qself.ty.make(offset + 1, id, scx)?;
258 let prefix = if qself.position == 0 {
259 format!("<{}>::", nested_ty.text)
260 } else if qself.position == 1 {
261 let first = pprust::path_segment_to_string(&path.segments[0]);
262 format!("<{} as {}>::", nested_ty.text, first)
264 // FIXME handle path instead of elipses.
265 format!("<{} as ...>::", nested_ty.text)
268 let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?);
269 let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
270 let id = id_from_def_id(res.def_id());
271 if path.segments.len() - qself.position == 1 {
272 let start = offset + prefix.len();
273 let end = start + name.len();
276 text: prefix + &name,
278 refs: vec![SigElement { id, start, end }],
281 let start = offset + prefix.len() + 5;
282 let end = start + name.len();
283 // FIXME should put the proper path in there, not elipses.
285 text: prefix + "...::" + &name,
287 refs: vec![SigElement { id, start, end }],
291 ast::TyKind::TraitObject(ref bounds, ..) => {
292 // FIXME recurse into bounds
293 let nested = pprust::bounds_to_string(bounds);
296 ast::TyKind::ImplTrait(_, ref bounds) => {
297 // FIXME recurse into bounds
298 let nested = pprust::bounds_to_string(bounds);
299 Ok(text_sig(format!("impl {}", nested)))
301 ast::TyKind::Array(ref ty, ref v) => {
302 let nested_ty = ty.make(offset + 1, id, scx)?;
303 let expr = pprust::expr_to_string(&v.value).replace('\n', " ");
304 let text = format!("[{}; {}]", nested_ty.text, expr);
305 Ok(replace_text(nested_ty, text))
307 ast::TyKind::Typeof(_)
310 | ast::TyKind::ImplicitSelf
311 | ast::TyKind::Mac(_) => Err("Ty"),
316 impl Sig for ast::Item {
317 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
318 let id = Some(self.id);
321 ast::ItemKind::Static(ref ty, m, ref expr) => {
322 let mut text = "static ".to_owned();
323 if m == ast::Mutability::Mut {
324 text.push_str("mut ");
326 let name = self.ident.to_string();
327 let defs = vec![SigElement {
328 id: id_from_node_id(self.id, scx),
329 start: offset + text.len(),
330 end: offset + text.len() + name.len(),
332 text.push_str(&name);
335 let ty = ty.make(offset + text.len(), id, scx)?;
336 text.push_str(&ty.text);
337 text.push_str(" = ");
339 let expr = pprust::expr_to_string(expr).replace('\n', " ");
340 text.push_str(&expr);
343 Ok(extend_sig(ty, text, defs, vec![]))
345 ast::ItemKind::Const(ref ty, ref expr) => {
346 let mut text = "const ".to_owned();
347 let name = self.ident.to_string();
348 let defs = vec![SigElement {
349 id: id_from_node_id(self.id, scx),
350 start: offset + text.len(),
351 end: offset + text.len() + name.len(),
353 text.push_str(&name);
356 let ty = ty.make(offset + text.len(), id, scx)?;
357 text.push_str(&ty.text);
358 text.push_str(" = ");
360 let expr = pprust::expr_to_string(expr).replace('\n', " ");
361 text.push_str(&expr);
364 Ok(extend_sig(ty, text, defs, vec![]))
366 ast::ItemKind::Fn(ast::FnSig { ref decl, header }, ref generics, _) => {
367 let mut text = String::new();
368 if let ast::Const::Yes(_) = header.constness {
369 text.push_str("const ");
371 if header.asyncness.is_async() {
372 text.push_str("async ");
374 if let ast::Unsafe::Yes(_) = header.unsafety {
375 text.push_str("unsafe ");
377 push_extern(&mut text, header.ext);
378 text.push_str("fn ");
380 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
383 for i in &decl.inputs {
384 // FIXME should descend into patterns to add defs.
385 sig.text.push_str(&pprust::pat_to_string(&i.pat));
386 sig.text.push_str(": ");
387 let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
388 sig.text.push_str(&nested.text);
390 sig.defs.extend(nested.defs.into_iter());
391 sig.refs.extend(nested.refs.into_iter());
395 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
396 sig.text.push_str(" -> ");
397 let nested = t.make(offset + sig.text.len(), None, scx)?;
398 sig.text.push_str(&nested.text);
399 sig.defs.extend(nested.defs.into_iter());
400 sig.refs.extend(nested.refs.into_iter());
402 sig.text.push_str(" {}");
406 ast::ItemKind::Mod(ref _mod) => {
407 let mut text = "mod ".to_owned();
408 let name = self.ident.to_string();
409 let defs = vec![SigElement {
410 id: id_from_node_id(self.id, scx),
411 start: offset + text.len(),
412 end: offset + text.len() + name.len(),
414 text.push_str(&name);
415 // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one.
418 Ok(Signature { text, defs, refs: vec![] })
420 ast::ItemKind::TyAlias(ref ty, ref generics) => {
421 let text = "type ".to_owned();
422 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
424 sig.text.push_str(" = ");
425 let ty = ty.make(offset + sig.text.len(), id, scx)?;
426 sig.text.push_str(&ty.text);
429 Ok(merge_sigs(sig.text.clone(), vec![sig, ty]))
431 ast::ItemKind::Enum(_, ref generics) => {
432 let text = "enum ".to_owned();
433 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
434 sig.text.push_str(" {}");
437 ast::ItemKind::Struct(_, ref generics) => {
438 let text = "struct ".to_owned();
439 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
440 sig.text.push_str(" {}");
443 ast::ItemKind::Union(_, ref generics) => {
444 let text = "union ".to_owned();
445 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
446 sig.text.push_str(" {}");
449 ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
450 let mut text = String::new();
452 if is_auto == ast::IsAuto::Yes {
453 text.push_str("auto ");
456 if let ast::Unsafe::Yes(_) = unsafety {
457 text.push_str("unsafe ");
459 text.push_str("trait ");
460 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
462 if !bounds.is_empty() {
463 sig.text.push_str(": ");
464 sig.text.push_str(&pprust::bounds_to_string(bounds));
466 // FIXME where clause
467 sig.text.push_str(" {}");
471 ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
472 let mut text = String::new();
473 text.push_str("trait ");
474 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
476 if !bounds.is_empty() {
477 sig.text.push_str(" = ");
478 sig.text.push_str(&pprust::bounds_to_string(bounds));
480 // FIXME where clause
481 sig.text.push_str(";");
485 ast::ItemKind::Impl {
495 let mut text = String::new();
496 if let ast::Defaultness::Default = defaultness {
497 text.push_str("default ");
499 if let ast::Unsafe::Yes(_) = unsafety {
500 text.push_str("unsafe ");
502 text.push_str("impl");
503 if let ast::Const::Yes(_) = constness {
504 text.push_str(" const");
507 let generics_sig = generics.make(offset + text.len(), id, scx)?;
508 text.push_str(&generics_sig.text);
512 let trait_sig = if let Some(ref t) = *of_trait {
513 if polarity == ast::ImplPolarity::Negative {
516 let trait_sig = t.path.make(offset + text.len(), id, scx)?;
517 text.push_str(&trait_sig.text);
518 text.push_str(" for ");
521 text_sig(String::new())
524 let ty_sig = self_ty.make(offset + text.len(), id, scx)?;
525 text.push_str(&ty_sig.text);
527 text.push_str(" {}");
529 Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig]))
531 // FIXME where clause
533 ast::ItemKind::ForeignMod(_) => Err("extern mod"),
534 ast::ItemKind::GlobalAsm(_) => Err("glboal asm"),
535 ast::ItemKind::ExternCrate(_) => Err("extern crate"),
536 // FIXME should implement this (e.g., pub use).
537 ast::ItemKind::Use(_) => Err("import"),
538 ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"),
543 impl Sig for ast::Path {
544 fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
545 let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
547 let (name, start, end) = match res {
548 Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
549 return Ok(Signature {
550 text: pprust::path_to_string(self),
555 Res::Def(DefKind::AssocConst, _)
556 | Res::Def(DefKind::Variant, _)
557 | Res::Def(DefKind::Ctor(..), _) => {
558 let len = self.segments.len();
560 return Err("Bad path");
562 // FIXME: really we should descend into the generics here and add SigElements for
564 // FIXME: would be nice to have a def for the first path segment.
565 let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]);
566 let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]);
567 let start = offset + seg1.len() + 2;
568 (format!("{}::{}", seg1, seg2), start, start + seg2.len())
571 let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?);
572 let end = offset + name.len();
577 let id = id_from_def_id(res.def_id());
578 Ok(Signature { text: name, defs: vec![], refs: vec![SigElement { id, start, end }] })
582 // This does not cover the where clause, which must be processed separately.
583 impl Sig for ast::Generics {
584 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
585 if self.params.is_empty() {
586 return Ok(text_sig(String::new()));
589 let mut text = "<".to_owned();
591 let mut defs = Vec::with_capacity(self.params.len());
592 for param in &self.params {
593 let mut param_text = String::new();
594 if let ast::GenericParamKind::Const { .. } = param.kind {
595 param_text.push_str("const ");
597 param_text.push_str(¶m.ident.as_str());
598 defs.push(SigElement {
599 id: id_from_node_id(param.id, scx),
600 start: offset + text.len(),
601 end: offset + text.len() + param_text.as_str().len(),
603 if let ast::GenericParamKind::Const { ref ty } = param.kind {
604 param_text.push_str(": ");
605 param_text.push_str(&pprust::ty_to_string(&ty));
607 if !param.bounds.is_empty() {
608 param_text.push_str(": ");
610 ast::GenericParamKind::Lifetime { .. } => {
614 .map(|bound| match bound {
615 ast::GenericBound::Outlives(lt) => lt.ident.to_string(),
620 param_text.push_str(&bounds);
621 // FIXME add lifetime bounds refs.
623 ast::GenericParamKind::Type { .. } => {
624 param_text.push_str(&pprust::bounds_to_string(¶m.bounds));
625 // FIXME descend properly into bounds.
627 ast::GenericParamKind::Const { .. } => {
628 // Const generics cannot contain bounds.
632 text.push_str(¶m_text);
637 Ok(Signature { text, defs, refs: vec![] })
641 impl Sig for ast::StructField {
642 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
643 let mut text = String::new();
645 if let Some(ident) = self.ident {
646 text.push_str(&ident.to_string());
647 defs = Some(SigElement {
648 id: id_from_node_id(self.id, scx),
650 end: offset + text.len(),
655 let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?;
656 text.push_str(&ty_sig.text);
658 ty_sig.defs.extend(defs.into_iter());
663 impl Sig for ast::Variant {
664 fn make(&self, offset: usize, parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
665 let mut text = self.ident.to_string();
667 ast::VariantData::Struct(ref fields, r) => {
668 let id = parent_id.unwrap();
669 let name_def = SigElement {
670 id: id_from_node_id(id, scx),
672 end: offset + text.len(),
674 text.push_str(" { ");
675 let mut defs = vec![name_def];
676 let mut refs = vec![];
678 text.push_str("/* parse error */ ");
681 let field_sig = f.make(offset + text.len(), Some(id), scx)?;
682 text.push_str(&field_sig.text);
684 defs.extend(field_sig.defs.into_iter());
685 refs.extend(field_sig.refs.into_iter());
689 Ok(Signature { text, defs, refs })
691 ast::VariantData::Tuple(ref fields, id) => {
692 let name_def = SigElement {
693 id: id_from_node_id(id, scx),
695 end: offset + text.len(),
698 let mut defs = vec![name_def];
699 let mut refs = vec![];
701 let field_sig = f.make(offset + text.len(), Some(id), scx)?;
702 text.push_str(&field_sig.text);
704 defs.extend(field_sig.defs.into_iter());
705 refs.extend(field_sig.refs.into_iter());
708 Ok(Signature { text, defs, refs })
710 ast::VariantData::Unit(id) => {
711 let name_def = SigElement {
712 id: id_from_node_id(id, scx),
714 end: offset + text.len(),
716 Ok(Signature { text, defs: vec![name_def], refs: vec![] })
722 impl Sig for ast::ForeignItem {
723 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
724 let id = Some(self.id);
726 ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
727 let decl = &sig.decl;
728 let mut text = String::new();
729 text.push_str("fn ");
731 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
734 for i in &decl.inputs {
735 // FIXME should descend into patterns to add defs.
736 sig.text.push_str(&pprust::pat_to_string(&i.pat));
737 sig.text.push_str(": ");
738 let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
739 sig.text.push_str(&nested.text);
741 sig.defs.extend(nested.defs.into_iter());
742 sig.refs.extend(nested.refs.into_iter());
746 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
747 sig.text.push_str(" -> ");
748 let nested = t.make(offset + sig.text.len(), None, scx)?;
749 sig.text.push_str(&nested.text);
750 sig.defs.extend(nested.defs.into_iter());
751 sig.refs.extend(nested.refs.into_iter());
757 ast::ForeignItemKind::Static(ref ty, m) => {
758 let mut text = "static ".to_owned();
759 if m == ast::Mutability::Mut {
760 text.push_str("mut ");
762 let name = self.ident.to_string();
763 let defs = vec![SigElement {
764 id: id_from_node_id(self.id, scx),
765 start: offset + text.len(),
766 end: offset + text.len() + name.len(),
768 text.push_str(&name);
771 let ty_sig = ty.make(offset + text.len(), id, scx)?;
774 Ok(extend_sig(ty_sig, text, defs, vec![]))
776 ast::ForeignItemKind::Ty => {
777 let mut text = "type ".to_owned();
778 let name = self.ident.to_string();
779 let defs = vec![SigElement {
780 id: id_from_node_id(self.id, scx),
781 start: offset + text.len(),
782 end: offset + text.len() + name.len(),
784 text.push_str(&name);
787 Ok(Signature { text: text, defs: defs, refs: vec![] })
789 ast::ForeignItemKind::Macro(..) => Err("macro"),
794 fn name_and_generics(
797 generics: &ast::Generics,
800 scx: &SaveContext<'_, '_>,
802 let name = name.to_string();
803 let def = SigElement {
804 id: id_from_node_id(id, scx),
805 start: offset + text.len(),
806 end: offset + text.len() + name.len(),
808 text.push_str(&name);
809 let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?;
810 // FIXME where clause
811 let text = format!("{}{}", text, generics.text);
812 Ok(extend_sig(generics, text, vec![def], vec![]))
815 fn make_assoc_type_signature(
818 bounds: Option<&ast::GenericBounds>,
819 default: Option<&ast::Ty>,
820 scx: &SaveContext<'_, '_>,
822 let mut text = "type ".to_owned();
823 let name = ident.to_string();
824 let mut defs = vec![SigElement {
825 id: id_from_node_id(id, scx),
827 end: text.len() + name.len(),
829 let mut refs = vec![];
830 text.push_str(&name);
831 if let Some(bounds) = bounds {
833 // FIXME should descend into bounds
834 text.push_str(&pprust::bounds_to_string(bounds));
836 if let Some(default) = default {
837 text.push_str(" = ");
838 let ty_sig = default.make(text.len(), Some(id), scx)?;
839 text.push_str(&ty_sig.text);
840 defs.extend(ty_sig.defs.into_iter());
841 refs.extend(ty_sig.refs.into_iter());
844 Ok(Signature { text, defs, refs })
847 fn make_assoc_const_signature(
851 default: Option<&ast::Expr>,
852 scx: &SaveContext<'_, '_>,
854 let mut text = "const ".to_owned();
855 let name = ident.to_string();
856 let mut defs = vec![SigElement {
857 id: id_from_node_id(id, scx),
859 end: text.len() + name.len(),
861 let mut refs = vec![];
862 text.push_str(&name);
865 let ty_sig = ty.make(text.len(), Some(id), scx)?;
866 text.push_str(&ty_sig.text);
867 defs.extend(ty_sig.defs.into_iter());
868 refs.extend(ty_sig.refs.into_iter());
870 if let Some(default) = default {
871 text.push_str(" = ");
872 text.push_str(&pprust::expr_to_string(default));
875 Ok(Signature { text, defs, refs })
878 fn make_method_signature(
881 generics: &ast::Generics,
883 scx: &SaveContext<'_, '_>,
885 // FIXME code dup with function signature
886 let mut text = String::new();
887 if let ast::Const::Yes(_) = m.header.constness {
888 text.push_str("const ");
890 if m.header.asyncness.is_async() {
891 text.push_str("async ");
893 if let ast::Unsafe::Yes(_) = m.header.unsafety {
894 text.push_str("unsafe ");
896 push_extern(&mut text, m.header.ext);
897 text.push_str("fn ");
899 let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
902 for i in &m.decl.inputs {
903 // FIXME should descend into patterns to add defs.
904 sig.text.push_str(&pprust::pat_to_string(&i.pat));
905 sig.text.push_str(": ");
906 let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?;
907 sig.text.push_str(&nested.text);
909 sig.defs.extend(nested.defs.into_iter());
910 sig.refs.extend(nested.refs.into_iter());
914 if let ast::FunctionRetTy::Ty(ref t) = m.decl.output {
915 sig.text.push_str(" -> ");
916 let nested = t.make(sig.text.len(), None, scx)?;
917 sig.text.push_str(&nested.text);
918 sig.defs.extend(nested.defs.into_iter());
919 sig.refs.extend(nested.refs.into_iter());
921 sig.text.push_str(" {}");