1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // A signature is a string representation of an item's type signature, excluding
12 // any body. It also includes ids for any defs or refs in the signature. For
16 // fn foo(x: String) {
20 // The signature string is something like "fn foo(x: String) {}" and the signature
21 // will have defs for `foo` and `x` and a ref for `String`.
23 // All signature text should parse in the correct context (i.e., in a module or
24 // impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a
25 // signature is not guaranteed to be stable (it may improve or change as the
26 // syntax changes, or whitespace or punctuation may change). It is also likely
27 // not to be pretty - no attempt is made to prettify the text. It is recommended
28 // that clients run the text through Rustfmt.
30 // This module generates Signatures for items by walking the AST and looking up
33 // Signatures do not include visibility info. I'm not sure if this is a feature
34 // or an ommission (FIXME).
36 // FIXME where clauses need implementing, defs/refs in generics are mostly missing.
38 use {id_from_def_id, id_from_node_id, SaveContext};
40 use rls_data::{SigElement, Signature};
42 use rustc::hir::def::Def;
43 use syntax::ast::{self, NodeId};
44 use syntax::print::pprust;
47 pub fn item_signature(item: &ast::Item, scx: &SaveContext) -> Option<Signature> {
48 if !scx.config.signatures {
51 item.make(0, None, scx).ok()
54 pub fn foreign_item_signature(item: &ast::ForeignItem, scx: &SaveContext) -> Option<Signature> {
55 if !scx.config.signatures {
58 item.make(0, None, scx).ok()
61 /// Signature for a struct or tuple field declaration.
62 /// Does not include a trailing comma.
63 pub fn field_signature(field: &ast::StructField, scx: &SaveContext) -> Option<Signature> {
64 if !scx.config.signatures {
67 field.make(0, None, scx).ok()
70 /// Does not include a trailing comma.
71 pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext) -> Option<Signature> {
72 if !scx.config.signatures {
75 variant.node.make(0, None, scx).ok()
78 pub fn method_signature(
81 generics: &ast::Generics,
84 ) -> Option<Signature> {
85 if !scx.config.signatures {
88 make_method_signature(id, ident, generics, m, scx).ok()
91 pub fn assoc_const_signature(
95 default: Option<&ast::Expr>,
97 ) -> Option<Signature> {
98 if !scx.config.signatures {
101 make_assoc_const_signature(id, ident, ty, default, scx).ok()
104 pub fn assoc_type_signature(
107 bounds: Option<&ast::GenericBounds>,
108 default: Option<&ast::Ty>,
110 ) -> Option<Signature> {
111 if !scx.config.signatures {
114 make_assoc_type_signature(id, ident, bounds, default, scx).ok()
117 type Result = ::std::result::Result<Signature, &'static str>;
120 fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext) -> Result;
126 defs: Vec<SigElement>,
127 refs: Vec<SigElement>,
130 sig.defs.extend(defs.into_iter());
131 sig.refs.extend(refs.into_iter());
135 fn replace_text(mut sig: Signature, text: String) -> Signature {
140 fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature {
141 let mut result = Signature {
147 let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip();
151 .extend(defs.into_iter().flat_map(|ds| ds.into_iter()));
154 .extend(refs.into_iter().flat_map(|rs| rs.into_iter()));
159 fn text_sig(text: String) -> Signature {
167 impl Sig for ast::Ty {
168 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
169 let id = Some(self.id);
171 ast::TyKind::Slice(ref ty) => {
172 let nested = ty.make(offset + 1, id, scx)?;
173 let text = format!("[{}]", nested.text);
174 Ok(replace_text(nested, text))
176 ast::TyKind::Ptr(ref mt) => {
177 let prefix = match mt.mutbl {
178 ast::Mutability::Mutable => "*mut ",
179 ast::Mutability::Immutable => "*const ",
181 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
182 let text = format!("{}{}", prefix, nested.text);
183 Ok(replace_text(nested, text))
185 ast::TyKind::Rptr(ref lifetime, ref mt) => {
186 let mut prefix = "&".to_owned();
187 if let &Some(ref l) = lifetime {
188 prefix.push_str(&l.ident.to_string());
191 if let ast::Mutability::Mutable = mt.mutbl {
192 prefix.push_str("mut ");
195 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
196 let text = format!("{}{}", prefix, nested.text);
197 Ok(replace_text(nested, text))
199 ast::TyKind::Never => Ok(text_sig("!".to_owned())),
200 ast::TyKind::Tup(ref ts) => {
201 let mut text = "(".to_owned();
202 let mut defs = vec![];
203 let mut refs = vec![];
205 let nested = t.make(offset + text.len(), id, scx)?;
206 text.push_str(&nested.text);
208 defs.extend(nested.defs.into_iter());
209 refs.extend(nested.refs.into_iter());
212 Ok(Signature { text, defs, refs })
214 ast::TyKind::Paren(ref ty) => {
215 let nested = ty.make(offset + 1, id, scx)?;
216 let text = format!("({})", nested.text);
217 Ok(replace_text(nested, text))
219 ast::TyKind::BareFn(ref f) => {
220 let mut text = String::new();
221 if !f.generic_params.is_empty() {
222 // FIXME defs, bounds on lifetimes
223 text.push_str("for<");
224 text.push_str(&f.generic_params
226 .filter_map(|param| match param.kind {
227 ast::GenericParamKind::Lifetime { .. } => {
228 Some(param.ident.to_string())
237 if f.unsafety == ast::Unsafety::Unsafe {
238 text.push_str("unsafe ");
240 if f.abi != ::rustc_target::spec::abi::Abi::Rust {
241 text.push_str("extern");
242 text.push_str(&f.abi.to_string());
245 text.push_str("fn(");
247 let mut defs = vec![];
248 let mut refs = vec![];
249 for i in &f.decl.inputs {
250 let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?;
251 text.push_str(&nested.text);
253 defs.extend(nested.defs.into_iter());
254 refs.extend(nested.refs.into_iter());
257 if let ast::FunctionRetTy::Ty(ref t) = f.decl.output {
258 text.push_str(" -> ");
259 let nested = t.make(offset + text.len(), None, scx)?;
260 text.push_str(&nested.text);
262 defs.extend(nested.defs.into_iter());
263 refs.extend(nested.refs.into_iter());
266 Ok(Signature { text, defs, refs })
268 ast::TyKind::Path(None, ref path) => path.make(offset, id, scx),
269 ast::TyKind::Path(Some(ref qself), ref path) => {
270 let nested_ty = qself.ty.make(offset + 1, id, scx)?;
271 let prefix = if qself.position == 0 {
272 format!("<{}>::", nested_ty.text)
273 } else if qself.position == 1 {
274 let first = pprust::path_segment_to_string(&path.segments[0]);
275 format!("<{} as {}>::", nested_ty.text, first)
277 // FIXME handle path instead of elipses.
278 format!("<{} as ...>::", nested_ty.text)
281 let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?);
282 let def = scx.get_path_def(id.ok_or("Missing id for Path")?);
283 let id = id_from_def_id(def.def_id());
284 if path.segments.len() - qself.position == 1 {
285 let start = offset + prefix.len();
286 let end = start + name.len();
289 text: prefix + &name,
291 refs: vec![SigElement { id, start, end }],
294 let start = offset + prefix.len() + 5;
295 let end = start + name.len();
296 // FIXME should put the proper path in there, not elipses.
298 text: prefix + "...::" + &name,
300 refs: vec![SigElement { id, start, end }],
304 ast::TyKind::TraitObject(ref bounds, ..) => {
305 // FIXME recurse into bounds
306 let nested = pprust::bounds_to_string(bounds);
309 ast::TyKind::ImplTrait(_, ref bounds) => {
310 // FIXME recurse into bounds
311 let nested = pprust::bounds_to_string(bounds);
312 Ok(text_sig(format!("impl {}", nested)))
314 ast::TyKind::Array(ref ty, ref v) => {
315 let nested_ty = ty.make(offset + 1, id, scx)?;
316 let expr = pprust::expr_to_string(&v.value).replace('\n', " ");
317 let text = format!("[{}; {}]", nested_ty.text, expr);
318 Ok(replace_text(nested_ty, text))
320 ast::TyKind::Typeof(_) |
323 ast::TyKind::ImplicitSelf |
324 ast::TyKind::Mac(_) => Err("Ty"),
329 impl Sig for ast::Item {
330 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
331 let id = Some(self.id);
334 ast::ItemKind::Static(ref ty, m, ref expr) => {
335 let mut text = "static ".to_owned();
336 if m == ast::Mutability::Mutable {
337 text.push_str("mut ");
339 let name = self.ident.to_string();
342 id: id_from_node_id(self.id, scx),
343 start: offset + text.len(),
344 end: offset + text.len() + name.len(),
347 text.push_str(&name);
350 let ty = ty.make(offset + text.len(), id, scx)?;
351 text.push_str(&ty.text);
352 text.push_str(" = ");
354 let expr = pprust::expr_to_string(expr).replace('\n', " ");
355 text.push_str(&expr);
358 Ok(extend_sig(ty, text, defs, vec![]))
360 ast::ItemKind::Const(ref ty, ref expr) => {
361 let mut text = "const ".to_owned();
362 let name = self.ident.to_string();
365 id: id_from_node_id(self.id, scx),
366 start: offset + text.len(),
367 end: offset + text.len() + name.len(),
370 text.push_str(&name);
373 let ty = ty.make(offset + text.len(), id, scx)?;
374 text.push_str(&ty.text);
375 text.push_str(" = ");
377 let expr = pprust::expr_to_string(expr).replace('\n', " ");
378 text.push_str(&expr);
381 Ok(extend_sig(ty, text, defs, vec![]))
383 ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
384 let mut text = String::new();
385 if header.constness.node == ast::Constness::Const {
386 text.push_str("const ");
388 if header.asyncness.is_async() {
389 text.push_str("async ");
391 if header.unsafety == ast::Unsafety::Unsafe {
392 text.push_str("unsafe ");
394 if header.abi != ::rustc_target::spec::abi::Abi::Rust {
395 text.push_str("extern");
396 text.push_str(&header.abi.to_string());
399 text.push_str("fn ");
401 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
404 for i in &decl.inputs {
405 // FIXME should descend into patterns to add defs.
406 sig.text.push_str(&pprust::pat_to_string(&i.pat));
407 sig.text.push_str(": ");
408 let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
409 sig.text.push_str(&nested.text);
411 sig.defs.extend(nested.defs.into_iter());
412 sig.refs.extend(nested.refs.into_iter());
416 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
417 sig.text.push_str(" -> ");
418 let nested = t.make(offset + sig.text.len(), None, scx)?;
419 sig.text.push_str(&nested.text);
420 sig.defs.extend(nested.defs.into_iter());
421 sig.refs.extend(nested.refs.into_iter());
423 sig.text.push_str(" {}");
427 ast::ItemKind::Mod(ref _mod) => {
428 let mut text = "mod ".to_owned();
429 let name = self.ident.to_string();
432 id: id_from_node_id(self.id, scx),
433 start: offset + text.len(),
434 end: offset + text.len() + name.len(),
437 text.push_str(&name);
438 // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one.
447 ast::ItemKind::Existential(ref bounds, ref generics) => {
448 let text = "existential type ".to_owned();
449 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
451 if !bounds.is_empty() {
452 sig.text.push_str(": ");
453 sig.text.push_str(&pprust::bounds_to_string(bounds));
459 ast::ItemKind::Ty(ref ty, ref generics) => {
460 let text = "type ".to_owned();
461 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
463 sig.text.push_str(" = ");
464 let ty = ty.make(offset + sig.text.len(), id, scx)?;
465 sig.text.push_str(&ty.text);
468 Ok(merge_sigs(sig.text.clone(), vec![sig, ty]))
470 ast::ItemKind::Enum(_, ref generics) => {
471 let text = "enum ".to_owned();
472 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
473 sig.text.push_str(" {}");
476 ast::ItemKind::Struct(_, ref generics) => {
477 let text = "struct ".to_owned();
478 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
479 sig.text.push_str(" {}");
482 ast::ItemKind::Union(_, ref generics) => {
483 let text = "union ".to_owned();
484 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
485 sig.text.push_str(" {}");
488 ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
489 let mut text = String::new();
491 if is_auto == ast::IsAuto::Yes {
492 text.push_str("auto ");
495 if unsafety == ast::Unsafety::Unsafe {
496 text.push_str("unsafe ");
498 text.push_str("trait ");
499 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
501 if !bounds.is_empty() {
502 sig.text.push_str(": ");
503 sig.text.push_str(&pprust::bounds_to_string(bounds));
505 // FIXME where clause
506 sig.text.push_str(" {}");
510 ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
511 let mut text = String::new();
512 text.push_str("trait ");
513 let mut sig = name_and_generics(text,
520 if !bounds.is_empty() {
521 sig.text.push_str(" = ");
522 sig.text.push_str(&pprust::bounds_to_string(bounds));
524 // FIXME where clause
525 sig.text.push_str(";");
538 let mut text = String::new();
539 if let ast::Defaultness::Default = defaultness {
540 text.push_str("default ");
542 if unsafety == ast::Unsafety::Unsafe {
543 text.push_str("unsafe ");
545 text.push_str("impl");
547 let generics_sig = generics.make(offset + text.len(), id, scx)?;
548 text.push_str(&generics_sig.text);
552 let trait_sig = if let Some(ref t) = *opt_trait {
553 if polarity == ast::ImplPolarity::Negative {
556 let trait_sig = t.path.make(offset + text.len(), id, scx)?;
557 text.push_str(&trait_sig.text);
558 text.push_str(" for ");
561 text_sig(String::new())
564 let ty_sig = ty.make(offset + text.len(), id, scx)?;
565 text.push_str(&ty_sig.text);
567 text.push_str(" {}");
569 Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig]))
571 // FIXME where clause
573 ast::ItemKind::ForeignMod(_) => Err("extern mod"),
574 ast::ItemKind::GlobalAsm(_) => Err("glboal asm"),
575 ast::ItemKind::ExternCrate(_) => Err("extern crate"),
576 // FIXME should implement this (e.g., pub use).
577 ast::ItemKind::Use(_) => Err("import"),
578 ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"),
583 impl Sig for ast::Path {
584 fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext) -> Result {
585 let def = scx.get_path_def(id.ok_or("Missing id for Path")?);
587 let (name, start, end) = match def {
588 Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {
589 return Ok(Signature {
590 text: pprust::path_to_string(self),
595 Def::AssociatedConst(..) | Def::Variant(..) | Def::VariantCtor(..) => {
596 let len = self.segments.len();
598 return Err("Bad path");
600 // FIXME: really we should descend into the generics here and add SigElements for
602 // FIXME: would be nice to have a def for the first path segment.
603 let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]);
604 let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]);
605 let start = offset + seg1.len() + 2;
606 (format!("{}::{}", seg1, seg2), start, start + seg2.len())
609 let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?);
610 let end = offset + name.len();
615 let id = id_from_def_id(def.def_id());
619 refs: vec![SigElement { id, start, end }],
624 // This does not cover the where clause, which must be processed separately.
625 impl Sig for ast::Generics {
626 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
627 if self.params.is_empty() {
628 return Ok(text_sig(String::new()));
631 let mut text = "<".to_owned();
633 let mut defs = Vec::with_capacity(self.params.len());
634 for param in &self.params {
635 let mut param_text = param.ident.to_string();
636 defs.push(SigElement {
637 id: id_from_node_id(param.id, scx),
638 start: offset + text.len(),
639 end: offset + text.len() + param_text.len(),
641 if !param.bounds.is_empty() {
642 param_text.push_str(": ");
644 ast::GenericParamKind::Lifetime { .. } => {
645 let bounds = param.bounds.iter()
646 .map(|bound| match bound {
647 ast::GenericBound::Outlives(lt) => lt.ident.to_string(),
652 param_text.push_str(&bounds);
653 // FIXME add lifetime bounds refs.
655 ast::GenericParamKind::Type { .. } => {
656 param_text.push_str(&pprust::bounds_to_string(¶m.bounds));
657 // FIXME descend properly into bounds.
661 text.push_str(¶m_text);
674 impl Sig for ast::StructField {
675 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
676 let mut text = String::new();
678 if let Some(ident) = self.ident {
679 text.push_str(&ident.to_string());
680 defs = Some(SigElement {
681 id: id_from_node_id(self.id, scx),
683 end: offset + text.len(),
688 let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?;
689 text.push_str(&ty_sig.text);
691 ty_sig.defs.extend(defs.into_iter());
697 impl Sig for ast::Variant_ {
698 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
699 let mut text = self.ident.to_string();
701 ast::VariantData::Struct(ref fields, id) => {
702 let name_def = SigElement {
703 id: id_from_node_id(id, scx),
705 end: offset + text.len(),
707 text.push_str(" { ");
708 let mut defs = vec![name_def];
709 let mut refs = vec![];
711 let field_sig = f.make(offset + text.len(), Some(id), scx)?;
712 text.push_str(&field_sig.text);
714 defs.extend(field_sig.defs.into_iter());
715 refs.extend(field_sig.refs.into_iter());
718 Ok(Signature { text, defs, refs })
720 ast::VariantData::Tuple(ref fields, id) => {
721 let name_def = SigElement {
722 id: id_from_node_id(id, scx),
724 end: offset + text.len(),
727 let mut defs = vec![name_def];
728 let mut refs = vec![];
730 let field_sig = f.make(offset + text.len(), Some(id), scx)?;
731 text.push_str(&field_sig.text);
733 defs.extend(field_sig.defs.into_iter());
734 refs.extend(field_sig.refs.into_iter());
737 Ok(Signature { text, defs, refs })
739 ast::VariantData::Unit(id) => {
740 let name_def = SigElement {
741 id: id_from_node_id(id, scx),
743 end: offset + text.len(),
747 defs: vec![name_def],
755 impl Sig for ast::ForeignItem {
756 fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
757 let id = Some(self.id);
759 ast::ForeignItemKind::Fn(ref decl, ref generics) => {
760 let mut text = String::new();
761 text.push_str("fn ");
763 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
766 for i in &decl.inputs {
767 // FIXME should descend into patterns to add defs.
768 sig.text.push_str(&pprust::pat_to_string(&i.pat));
769 sig.text.push_str(": ");
770 let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
771 sig.text.push_str(&nested.text);
773 sig.defs.extend(nested.defs.into_iter());
774 sig.refs.extend(nested.refs.into_iter());
778 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
779 sig.text.push_str(" -> ");
780 let nested = t.make(offset + sig.text.len(), None, scx)?;
781 sig.text.push_str(&nested.text);
782 sig.defs.extend(nested.defs.into_iter());
783 sig.refs.extend(nested.refs.into_iter());
789 ast::ForeignItemKind::Static(ref ty, m) => {
790 let mut text = "static ".to_owned();
792 text.push_str("mut ");
794 let name = self.ident.to_string();
797 id: id_from_node_id(self.id, scx),
798 start: offset + text.len(),
799 end: offset + text.len() + name.len(),
802 text.push_str(&name);
805 let ty_sig = ty.make(offset + text.len(), id, scx)?;
808 Ok(extend_sig(ty_sig, text, defs, vec![]))
810 ast::ForeignItemKind::Ty => {
811 let mut text = "type ".to_owned();
812 let name = self.ident.to_string();
815 id: id_from_node_id(self.id, scx),
816 start: offset + text.len(),
817 end: offset + text.len() + name.len(),
820 text.push_str(&name);
829 ast::ForeignItemKind::Macro(..) => Err("macro"),
834 fn name_and_generics(
837 generics: &ast::Generics,
842 let name = name.to_string();
843 let def = SigElement {
844 id: id_from_node_id(id, scx),
845 start: offset + text.len(),
846 end: offset + text.len() + name.len(),
848 text.push_str(&name);
849 let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?;
850 // FIXME where clause
851 let text = format!("{}{}", text, generics.text);
852 Ok(extend_sig(generics, text, vec![def], vec![]))
856 fn make_assoc_type_signature(
859 bounds: Option<&ast::GenericBounds>,
860 default: Option<&ast::Ty>,
863 let mut text = "type ".to_owned();
864 let name = ident.to_string();
867 id: id_from_node_id(id, scx),
869 end: text.len() + name.len(),
872 let mut refs = vec![];
873 text.push_str(&name);
874 if let Some(bounds) = bounds {
876 // FIXME should descend into bounds
877 text.push_str(&pprust::bounds_to_string(bounds));
879 if let Some(default) = default {
880 text.push_str(" = ");
881 let ty_sig = default.make(text.len(), Some(id), scx)?;
882 text.push_str(&ty_sig.text);
883 defs.extend(ty_sig.defs.into_iter());
884 refs.extend(ty_sig.refs.into_iter());
887 Ok(Signature { text, defs, refs })
890 fn make_assoc_const_signature(
894 default: Option<&ast::Expr>,
897 let mut text = "const ".to_owned();
898 let name = ident.to_string();
901 id: id_from_node_id(id, scx),
903 end: text.len() + name.len(),
906 let mut refs = vec![];
907 text.push_str(&name);
910 let ty_sig = ty.make(text.len(), Some(id), scx)?;
911 text.push_str(&ty_sig.text);
912 defs.extend(ty_sig.defs.into_iter());
913 refs.extend(ty_sig.refs.into_iter());
915 if let Some(default) = default {
916 text.push_str(" = ");
917 text.push_str(&pprust::expr_to_string(default));
920 Ok(Signature { text, defs, refs })
923 fn make_method_signature(
926 generics: &ast::Generics,
930 // FIXME code dup with function signature
931 let mut text = String::new();
932 if m.header.constness.node == ast::Constness::Const {
933 text.push_str("const ");
935 if m.header.asyncness.is_async() {
936 text.push_str("async ");
938 if m.header.unsafety == ast::Unsafety::Unsafe {
939 text.push_str("unsafe ");
941 if m.header.abi != ::rustc_target::spec::abi::Abi::Rust {
942 text.push_str("extern");
943 text.push_str(&m.header.abi.to_string());
946 text.push_str("fn ");
948 let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
951 for i in &m.decl.inputs {
952 // FIXME should descend into patterns to add defs.
953 sig.text.push_str(&pprust::pat_to_string(&i.pat));
954 sig.text.push_str(": ");
955 let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?;
956 sig.text.push_str(&nested.text);
958 sig.defs.extend(nested.defs.into_iter());
959 sig.refs.extend(nested.refs.into_iter());
963 if let ast::FunctionRetTy::Ty(ref t) = m.decl.output {
964 sig.text.push_str(" -> ");
965 let nested = t.make(sig.text.len(), None, scx)?;
966 sig.text.push_str(&nested.text);
967 sig.defs.extend(nested.defs.into_iter());
968 sig.refs.extend(nested.refs.into_iter());
970 sig.text.push_str(" {}");