]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/sig.rs
Remove weasel word in docs for iter's take_while()
[rust.git] / src / librustc_save_analysis / sig.rs
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
28 use {id_from_def_id, id_from_node_id, SaveContext};
29
30 use rls_data::{SigElement, Signature};
31
32 use rustc::hir::def::Def;
33 use syntax::ast::{self, NodeId};
34 use syntax::print::pprust;
35
36
37 pub fn item_signature(item: &ast::Item, scx: &SaveContext) -> Option<Signature> {
38     if !scx.config.signatures {
39         return None;
40     }
41     item.make(0, None, scx).ok()
42 }
43
44 pub fn foreign_item_signature(item: &ast::ForeignItem, scx: &SaveContext) -> Option<Signature> {
45     if !scx.config.signatures {
46         return None;
47     }
48     item.make(0, None, scx).ok()
49 }
50
51 /// Signature for a struct or tuple field declaration.
52 /// Does not include a trailing comma.
53 pub fn field_signature(field: &ast::StructField, scx: &SaveContext) -> Option<Signature> {
54     if !scx.config.signatures {
55         return None;
56     }
57     field.make(0, None, scx).ok()
58 }
59
60 /// Does not include a trailing comma.
61 pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext) -> Option<Signature> {
62     if !scx.config.signatures {
63         return None;
64     }
65     variant.node.make(0, None, scx).ok()
66 }
67
68 pub fn method_signature(
69     id: NodeId,
70     ident: ast::Ident,
71     generics: &ast::Generics,
72     m: &ast::MethodSig,
73     scx: &SaveContext,
74 ) -> Option<Signature> {
75     if !scx.config.signatures {
76         return None;
77     }
78     make_method_signature(id, ident, generics, m, scx).ok()
79 }
80
81 pub fn assoc_const_signature(
82     id: NodeId,
83     ident: ast::Name,
84     ty: &ast::Ty,
85     default: Option<&ast::Expr>,
86     scx: &SaveContext,
87 ) -> Option<Signature> {
88     if !scx.config.signatures {
89         return None;
90     }
91     make_assoc_const_signature(id, ident, ty, default, scx).ok()
92 }
93
94 pub fn assoc_type_signature(
95     id: NodeId,
96     ident: ast::Ident,
97     bounds: Option<&ast::GenericBounds>,
98     default: Option<&ast::Ty>,
99     scx: &SaveContext,
100 ) -> Option<Signature> {
101     if !scx.config.signatures {
102         return None;
103     }
104     make_assoc_type_signature(id, ident, bounds, default, scx).ok()
105 }
106
107 type Result = ::std::result::Result<Signature, &'static str>;
108
109 trait Sig {
110     fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext) -> Result;
111 }
112
113 fn extend_sig(
114     mut sig: Signature,
115     text: String,
116     defs: Vec<SigElement>,
117     refs: Vec<SigElement>,
118 ) -> Signature {
119     sig.text = text;
120     sig.defs.extend(defs.into_iter());
121     sig.refs.extend(refs.into_iter());
122     sig
123 }
124
125 fn replace_text(mut sig: Signature, text: String) -> Signature {
126     sig.text = text;
127     sig
128 }
129
130 fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature {
131     let mut result = Signature {
132         text,
133         defs: vec![],
134         refs: vec![],
135     };
136
137     let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip();
138
139     result
140         .defs
141         .extend(defs.into_iter().flat_map(|ds| ds.into_iter()));
142     result
143         .refs
144         .extend(refs.into_iter().flat_map(|rs| rs.into_iter()));
145
146     result
147 }
148
149 fn text_sig(text: String) -> Signature {
150     Signature {
151         text,
152         defs: vec![],
153         refs: vec![],
154     }
155 }
156
157 impl Sig for ast::Ty {
158     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
159         let id = Some(self.id);
160         match self.node {
161             ast::TyKind::Slice(ref ty) => {
162                 let nested = ty.make(offset + 1, id, scx)?;
163                 let text = format!("[{}]", nested.text);
164                 Ok(replace_text(nested, text))
165             }
166             ast::TyKind::Ptr(ref mt) => {
167                 let prefix = match mt.mutbl {
168                     ast::Mutability::Mutable => "*mut ",
169                     ast::Mutability::Immutable => "*const ",
170                 };
171                 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
172                 let text = format!("{}{}", prefix, nested.text);
173                 Ok(replace_text(nested, text))
174             }
175             ast::TyKind::Rptr(ref lifetime, ref mt) => {
176                 let mut prefix = "&".to_owned();
177                 if let &Some(ref l) = lifetime {
178                     prefix.push_str(&l.ident.to_string());
179                     prefix.push(' ');
180                 }
181                 if let ast::Mutability::Mutable = mt.mutbl {
182                     prefix.push_str("mut ");
183                 };
184
185                 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
186                 let text = format!("{}{}", prefix, nested.text);
187                 Ok(replace_text(nested, text))
188             }
189             ast::TyKind::Never => Ok(text_sig("!".to_owned())),
190             ast::TyKind::Tup(ref ts) => {
191                 let mut text = "(".to_owned();
192                 let mut defs = vec![];
193                 let mut refs = vec![];
194                 for t in ts {
195                     let nested = t.make(offset + text.len(), id, scx)?;
196                     text.push_str(&nested.text);
197                     text.push(',');
198                     defs.extend(nested.defs.into_iter());
199                     refs.extend(nested.refs.into_iter());
200                 }
201                 text.push(')');
202                 Ok(Signature { text, defs, refs })
203             }
204             ast::TyKind::Paren(ref ty) => {
205                 let nested = ty.make(offset + 1, id, scx)?;
206                 let text = format!("({})", nested.text);
207                 Ok(replace_text(nested, text))
208             }
209             ast::TyKind::BareFn(ref f) => {
210                 let mut text = String::new();
211                 if !f.generic_params.is_empty() {
212                     // FIXME defs, bounds on lifetimes
213                     text.push_str("for<");
214                     text.push_str(&f.generic_params
215                         .iter()
216                         .filter_map(|param| match param.kind {
217                             ast::GenericParamKind::Lifetime { .. } => {
218                                 Some(param.ident.to_string())
219                             }
220                             _ => None,
221                         })
222                         .collect::<Vec<_>>()
223                         .join(", "));
224                     text.push('>');
225                 }
226
227                 if f.unsafety == ast::Unsafety::Unsafe {
228                     text.push_str("unsafe ");
229                 }
230                 if f.abi != ::rustc_target::spec::abi::Abi::Rust {
231                     text.push_str("extern");
232                     text.push_str(&f.abi.to_string());
233                     text.push(' ');
234                 }
235                 text.push_str("fn(");
236
237                 let mut defs = vec![];
238                 let mut refs = vec![];
239                 for i in &f.decl.inputs {
240                     let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?;
241                     text.push_str(&nested.text);
242                     text.push(',');
243                     defs.extend(nested.defs.into_iter());
244                     refs.extend(nested.refs.into_iter());
245                 }
246                 text.push(')');
247                 if let ast::FunctionRetTy::Ty(ref t) = f.decl.output {
248                     text.push_str(" -> ");
249                     let nested = t.make(offset + text.len(), None, scx)?;
250                     text.push_str(&nested.text);
251                     text.push(',');
252                     defs.extend(nested.defs.into_iter());
253                     refs.extend(nested.refs.into_iter());
254                 }
255
256                 Ok(Signature { text, defs, refs })
257             }
258             ast::TyKind::Path(None, ref path) => path.make(offset, id, scx),
259             ast::TyKind::Path(Some(ref qself), ref path) => {
260                 let nested_ty = qself.ty.make(offset + 1, id, scx)?;
261                 let prefix = if qself.position == 0 {
262                     format!("<{}>::", nested_ty.text)
263                 } else if qself.position == 1 {
264                     let first = pprust::path_segment_to_string(&path.segments[0]);
265                     format!("<{} as {}>::", nested_ty.text, first)
266                 } else {
267                     // FIXME handle path instead of elipses.
268                     format!("<{} as ...>::", nested_ty.text)
269                 };
270
271                 let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?);
272                 let def = scx.get_path_def(id.ok_or("Missing id for Path")?);
273                 let id = id_from_def_id(def.def_id());
274                 if path.segments.len() - qself.position == 1 {
275                     let start = offset + prefix.len();
276                     let end = start + name.len();
277
278                     Ok(Signature {
279                         text: prefix + &name,
280                         defs: vec![],
281                         refs: vec![SigElement { id, start, end }],
282                     })
283                 } else {
284                     let start = offset + prefix.len() + 5;
285                     let end = start + name.len();
286                     // FIXME should put the proper path in there, not elipses.
287                     Ok(Signature {
288                         text: prefix + "...::" + &name,
289                         defs: vec![],
290                         refs: vec![SigElement { id, start, end }],
291                     })
292                 }
293             }
294             ast::TyKind::TraitObject(ref bounds, ..) => {
295                 // FIXME recurse into bounds
296                 let nested = pprust::bounds_to_string(bounds);
297                 Ok(text_sig(nested))
298             }
299             ast::TyKind::ImplTrait(_, ref bounds) => {
300                 // FIXME recurse into bounds
301                 let nested = pprust::bounds_to_string(bounds);
302                 Ok(text_sig(format!("impl {}", nested)))
303             }
304             ast::TyKind::Array(ref ty, ref v) => {
305                 let nested_ty = ty.make(offset + 1, id, scx)?;
306                 let expr = pprust::expr_to_string(&v.value).replace('\n', " ");
307                 let text = format!("[{}; {}]", nested_ty.text, expr);
308                 Ok(replace_text(nested_ty, text))
309             }
310             ast::TyKind::Typeof(_) |
311             ast::TyKind::Infer |
312             ast::TyKind::Err |
313             ast::TyKind::ImplicitSelf |
314             ast::TyKind::Mac(_) => Err("Ty"),
315         }
316     }
317 }
318
319 impl Sig for ast::Item {
320     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
321         let id = Some(self.id);
322
323         match self.node {
324             ast::ItemKind::Static(ref ty, m, ref expr) => {
325                 let mut text = "static ".to_owned();
326                 if m == ast::Mutability::Mutable {
327                     text.push_str("mut ");
328                 }
329                 let name = self.ident.to_string();
330                 let defs = vec![
331                     SigElement {
332                         id: id_from_node_id(self.id, scx),
333                         start: offset + text.len(),
334                         end: offset + text.len() + name.len(),
335                     },
336                 ];
337                 text.push_str(&name);
338                 text.push_str(": ");
339
340                 let ty = ty.make(offset + text.len(), id, scx)?;
341                 text.push_str(&ty.text);
342                 text.push_str(" = ");
343
344                 let expr = pprust::expr_to_string(expr).replace('\n', " ");
345                 text.push_str(&expr);
346                 text.push(';');
347
348                 Ok(extend_sig(ty, text, defs, vec![]))
349             }
350             ast::ItemKind::Const(ref ty, ref expr) => {
351                 let mut text = "const ".to_owned();
352                 let name = self.ident.to_string();
353                 let defs = vec![
354                     SigElement {
355                         id: id_from_node_id(self.id, scx),
356                         start: offset + text.len(),
357                         end: offset + text.len() + name.len(),
358                     },
359                 ];
360                 text.push_str(&name);
361                 text.push_str(": ");
362
363                 let ty = ty.make(offset + text.len(), id, scx)?;
364                 text.push_str(&ty.text);
365                 text.push_str(" = ");
366
367                 let expr = pprust::expr_to_string(expr).replace('\n', " ");
368                 text.push_str(&expr);
369                 text.push(';');
370
371                 Ok(extend_sig(ty, text, defs, vec![]))
372             }
373             ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
374                 let mut text = String::new();
375                 if header.constness.node == ast::Constness::Const {
376                     text.push_str("const ");
377                 }
378                 if header.asyncness.is_async() {
379                     text.push_str("async ");
380                 }
381                 if header.unsafety == ast::Unsafety::Unsafe {
382                     text.push_str("unsafe ");
383                 }
384                 if header.abi != ::rustc_target::spec::abi::Abi::Rust {
385                     text.push_str("extern");
386                     text.push_str(&header.abi.to_string());
387                     text.push(' ');
388                 }
389                 text.push_str("fn ");
390
391                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
392
393                 sig.text.push('(');
394                 for i in &decl.inputs {
395                     // FIXME should descend into patterns to add defs.
396                     sig.text.push_str(&pprust::pat_to_string(&i.pat));
397                     sig.text.push_str(": ");
398                     let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
399                     sig.text.push_str(&nested.text);
400                     sig.text.push(',');
401                     sig.defs.extend(nested.defs.into_iter());
402                     sig.refs.extend(nested.refs.into_iter());
403                 }
404                 sig.text.push(')');
405
406                 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
407                     sig.text.push_str(" -> ");
408                     let nested = t.make(offset + sig.text.len(), None, scx)?;
409                     sig.text.push_str(&nested.text);
410                     sig.defs.extend(nested.defs.into_iter());
411                     sig.refs.extend(nested.refs.into_iter());
412                 }
413                 sig.text.push_str(" {}");
414
415                 Ok(sig)
416             }
417             ast::ItemKind::Mod(ref _mod) => {
418                 let mut text = "mod ".to_owned();
419                 let name = self.ident.to_string();
420                 let defs = vec![
421                     SigElement {
422                         id: id_from_node_id(self.id, scx),
423                         start: offset + text.len(),
424                         end: offset + text.len() + name.len(),
425                     },
426                 ];
427                 text.push_str(&name);
428                 // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one.
429                 text.push(';');
430
431                 Ok(Signature {
432                     text,
433                     defs,
434                     refs: vec![],
435                 })
436             }
437             ast::ItemKind::Existential(ref bounds, ref generics) => {
438                 let text = "existential type ".to_owned();
439                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
440
441                 if !bounds.is_empty() {
442                     sig.text.push_str(": ");
443                     sig.text.push_str(&pprust::bounds_to_string(bounds));
444                 }
445                 sig.text.push(';');
446
447                 Ok(sig)
448             }
449             ast::ItemKind::Ty(ref ty, ref generics) => {
450                 let text = "type ".to_owned();
451                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
452
453                 sig.text.push_str(" = ");
454                 let ty = ty.make(offset + sig.text.len(), id, scx)?;
455                 sig.text.push_str(&ty.text);
456                 sig.text.push(';');
457
458                 Ok(merge_sigs(sig.text.clone(), vec![sig, ty]))
459             }
460             ast::ItemKind::Enum(_, ref generics) => {
461                 let text = "enum ".to_owned();
462                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
463                 sig.text.push_str(" {}");
464                 Ok(sig)
465             }
466             ast::ItemKind::Struct(_, ref generics) => {
467                 let text = "struct ".to_owned();
468                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
469                 sig.text.push_str(" {}");
470                 Ok(sig)
471             }
472             ast::ItemKind::Union(_, ref generics) => {
473                 let text = "union ".to_owned();
474                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
475                 sig.text.push_str(" {}");
476                 Ok(sig)
477             }
478             ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
479                 let mut text = String::new();
480
481                 if is_auto == ast::IsAuto::Yes {
482                     text.push_str("auto ");
483                 }
484
485                 if unsafety == ast::Unsafety::Unsafe {
486                     text.push_str("unsafe ");
487                 }
488                 text.push_str("trait ");
489                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
490
491                 if !bounds.is_empty() {
492                     sig.text.push_str(": ");
493                     sig.text.push_str(&pprust::bounds_to_string(bounds));
494                 }
495                 // FIXME where clause
496                 sig.text.push_str(" {}");
497
498                 Ok(sig)
499             }
500             ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
501                 let mut text = String::new();
502                 text.push_str("trait ");
503                 let mut sig = name_and_generics(text,
504                                                 offset,
505                                                 generics,
506                                                 self.id,
507                                                 self.ident,
508                                                 scx)?;
509
510                 if !bounds.is_empty() {
511                     sig.text.push_str(" = ");
512                     sig.text.push_str(&pprust::bounds_to_string(bounds));
513                 }
514                 // FIXME where clause
515                 sig.text.push_str(";");
516
517                 Ok(sig)
518             }
519             ast::ItemKind::Impl(
520                 unsafety,
521                 polarity,
522                 defaultness,
523                 ref generics,
524                 ref opt_trait,
525                 ref ty,
526                 _,
527             ) => {
528                 let mut text = String::new();
529                 if let ast::Defaultness::Default = defaultness {
530                     text.push_str("default ");
531                 }
532                 if unsafety == ast::Unsafety::Unsafe {
533                     text.push_str("unsafe ");
534                 }
535                 text.push_str("impl");
536
537                 let generics_sig = generics.make(offset + text.len(), id, scx)?;
538                 text.push_str(&generics_sig.text);
539
540                 text.push(' ');
541
542                 let trait_sig = if let Some(ref t) = *opt_trait {
543                     if polarity == ast::ImplPolarity::Negative {
544                         text.push('!');
545                     }
546                     let trait_sig = t.path.make(offset + text.len(), id, scx)?;
547                     text.push_str(&trait_sig.text);
548                     text.push_str(" for ");
549                     trait_sig
550                 } else {
551                     text_sig(String::new())
552                 };
553
554                 let ty_sig = ty.make(offset + text.len(), id, scx)?;
555                 text.push_str(&ty_sig.text);
556
557                 text.push_str(" {}");
558
559                 Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig]))
560
561                 // FIXME where clause
562             }
563             ast::ItemKind::ForeignMod(_) => Err("extern mod"),
564             ast::ItemKind::GlobalAsm(_) => Err("glboal asm"),
565             ast::ItemKind::ExternCrate(_) => Err("extern crate"),
566             // FIXME should implement this (e.g., pub use).
567             ast::ItemKind::Use(_) => Err("import"),
568             ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"),
569         }
570     }
571 }
572
573 impl Sig for ast::Path {
574     fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext) -> Result {
575         let def = scx.get_path_def(id.ok_or("Missing id for Path")?);
576
577         let (name, start, end) = match def {
578             Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {
579                 return Ok(Signature {
580                     text: pprust::path_to_string(self),
581                     defs: vec![],
582                     refs: vec![],
583                 })
584             }
585             Def::AssociatedConst(..) | Def::Variant(..) | Def::VariantCtor(..) => {
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.
593                 let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]);
594                 let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]);
595                 let start = offset + seg1.len() + 2;
596                 (format!("{}::{}", seg1, seg2), start, start + seg2.len())
597             }
598             _ => {
599                 let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?);
600                 let end = offset + name.len();
601                 (name, offset, end)
602             }
603         };
604
605         let id = id_from_def_id(def.def_id());
606         Ok(Signature {
607             text: name,
608             defs: vec![],
609             refs: vec![SigElement { id, start, end }],
610         })
611     }
612 }
613
614 // This does not cover the where clause, which must be processed separately.
615 impl Sig for ast::Generics {
616     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
617         if self.params.is_empty() {
618             return Ok(text_sig(String::new()));
619         }
620
621         let mut text = "<".to_owned();
622
623         let mut defs = Vec::with_capacity(self.params.len());
624         for param in &self.params {
625             let mut param_text = param.ident.to_string();
626             defs.push(SigElement {
627                 id: id_from_node_id(param.id, scx),
628                 start: offset + text.len(),
629                 end: offset + text.len() + param_text.len(),
630             });
631             if !param.bounds.is_empty() {
632                 param_text.push_str(": ");
633                 match param.kind {
634                     ast::GenericParamKind::Lifetime { .. } => {
635                         let bounds = param.bounds.iter()
636                             .map(|bound| match bound {
637                                 ast::GenericBound::Outlives(lt) => lt.ident.to_string(),
638                                 _ => panic!(),
639                             })
640                             .collect::<Vec<_>>()
641                             .join(" + ");
642                         param_text.push_str(&bounds);
643                         // FIXME add lifetime bounds refs.
644                     }
645                     ast::GenericParamKind::Type { .. } => {
646                         param_text.push_str(&pprust::bounds_to_string(&param.bounds));
647                         // FIXME descend properly into bounds.
648                     }
649                 }
650             }
651             text.push_str(&param_text);
652             text.push(',');
653         }
654
655         text.push('>');
656         Ok(Signature {
657             text,
658             defs,
659             refs: vec![],
660         })
661     }
662 }
663
664 impl Sig for ast::StructField {
665     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
666         let mut text = String::new();
667         let mut defs = None;
668         if let Some(ident) = self.ident {
669             text.push_str(&ident.to_string());
670             defs = Some(SigElement {
671                 id: id_from_node_id(self.id, scx),
672                 start: offset,
673                 end: offset + text.len(),
674             });
675             text.push_str(": ");
676         }
677
678         let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?;
679         text.push_str(&ty_sig.text);
680         ty_sig.text = text;
681         ty_sig.defs.extend(defs.into_iter());
682         Ok(ty_sig)
683     }
684 }
685
686
687 impl Sig for ast::Variant_ {
688     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
689         let mut text = self.ident.to_string();
690         match self.data {
691             ast::VariantData::Struct(ref fields, id) => {
692                 let name_def = SigElement {
693                     id: id_from_node_id(id, scx),
694                     start: offset,
695                     end: offset + text.len(),
696                 };
697                 text.push_str(" { ");
698                 let mut defs = vec![name_def];
699                 let mut refs = vec![];
700                 for f in fields {
701                     let field_sig = f.make(offset + text.len(), Some(id), scx)?;
702                     text.push_str(&field_sig.text);
703                     text.push_str(", ");
704                     defs.extend(field_sig.defs.into_iter());
705                     refs.extend(field_sig.refs.into_iter());
706                 }
707                 text.push('}');
708                 Ok(Signature { text, defs, refs })
709             }
710             ast::VariantData::Tuple(ref fields, id) => {
711                 let name_def = SigElement {
712                     id: id_from_node_id(id, scx),
713                     start: offset,
714                     end: offset + text.len(),
715                 };
716                 text.push('(');
717                 let mut defs = vec![name_def];
718                 let mut refs = vec![];
719                 for f in fields {
720                     let field_sig = f.make(offset + text.len(), Some(id), scx)?;
721                     text.push_str(&field_sig.text);
722                     text.push_str(", ");
723                     defs.extend(field_sig.defs.into_iter());
724                     refs.extend(field_sig.refs.into_iter());
725                 }
726                 text.push(')');
727                 Ok(Signature { text, defs, refs })
728             }
729             ast::VariantData::Unit(id) => {
730                 let name_def = SigElement {
731                     id: id_from_node_id(id, scx),
732                     start: offset,
733                     end: offset + text.len(),
734                 };
735                 Ok(Signature {
736                     text,
737                     defs: vec![name_def],
738                     refs: vec![],
739                 })
740             }
741         }
742     }
743 }
744
745 impl Sig for ast::ForeignItem {
746     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) -> Result {
747         let id = Some(self.id);
748         match self.node {
749             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
750                 let mut text = String::new();
751                 text.push_str("fn ");
752
753                 let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
754
755                 sig.text.push('(');
756                 for i in &decl.inputs {
757                     // FIXME should descend into patterns to add defs.
758                     sig.text.push_str(&pprust::pat_to_string(&i.pat));
759                     sig.text.push_str(": ");
760                     let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
761                     sig.text.push_str(&nested.text);
762                     sig.text.push(',');
763                     sig.defs.extend(nested.defs.into_iter());
764                     sig.refs.extend(nested.refs.into_iter());
765                 }
766                 sig.text.push(')');
767
768                 if let ast::FunctionRetTy::Ty(ref t) = decl.output {
769                     sig.text.push_str(" -> ");
770                     let nested = t.make(offset + sig.text.len(), None, scx)?;
771                     sig.text.push_str(&nested.text);
772                     sig.defs.extend(nested.defs.into_iter());
773                     sig.refs.extend(nested.refs.into_iter());
774                 }
775                 sig.text.push(';');
776
777                 Ok(sig)
778             }
779             ast::ForeignItemKind::Static(ref ty, m) => {
780                 let mut text = "static ".to_owned();
781                 if m {
782                     text.push_str("mut ");
783                 }
784                 let name = self.ident.to_string();
785                 let defs = vec![
786                     SigElement {
787                         id: id_from_node_id(self.id, scx),
788                         start: offset + text.len(),
789                         end: offset + text.len() + name.len(),
790                     },
791                 ];
792                 text.push_str(&name);
793                 text.push_str(": ");
794
795                 let ty_sig = ty.make(offset + text.len(), id, scx)?;
796                 text.push(';');
797
798                 Ok(extend_sig(ty_sig, text, defs, vec![]))
799             }
800             ast::ForeignItemKind::Ty => {
801                 let mut text = "type ".to_owned();
802                 let name = self.ident.to_string();
803                 let defs = vec![
804                     SigElement {
805                         id: id_from_node_id(self.id, scx),
806                         start: offset + text.len(),
807                         end: offset + text.len() + name.len(),
808                     },
809                 ];
810                 text.push_str(&name);
811                 text.push(';');
812
813                 Ok(Signature {
814                     text: text,
815                     defs: defs,
816                     refs: vec![],
817                 })
818             }
819             ast::ForeignItemKind::Macro(..) => Err("macro"),
820         }
821     }
822 }
823
824 fn name_and_generics(
825     mut text: String,
826     offset: usize,
827     generics: &ast::Generics,
828     id: NodeId,
829     name: ast::Ident,
830     scx: &SaveContext,
831 ) -> Result {
832     let name = name.to_string();
833     let def = SigElement {
834         id: id_from_node_id(id, scx),
835         start: offset + text.len(),
836         end: offset + text.len() + name.len(),
837     };
838     text.push_str(&name);
839     let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?;
840     // FIXME where clause
841     let text = format!("{}{}", text, generics.text);
842     Ok(extend_sig(generics, text, vec![def], vec![]))
843 }
844
845
846 fn make_assoc_type_signature(
847     id: NodeId,
848     ident: ast::Ident,
849     bounds: Option<&ast::GenericBounds>,
850     default: Option<&ast::Ty>,
851     scx: &SaveContext,
852 ) -> Result {
853     let mut text = "type ".to_owned();
854     let name = ident.to_string();
855     let mut defs = vec![
856         SigElement {
857             id: id_from_node_id(id, scx),
858             start: text.len(),
859             end: text.len() + name.len(),
860         },
861     ];
862     let mut refs = vec![];
863     text.push_str(&name);
864     if let Some(bounds) = bounds {
865         text.push_str(": ");
866         // FIXME should descend into bounds
867         text.push_str(&pprust::bounds_to_string(bounds));
868     }
869     if let Some(default) = default {
870         text.push_str(" = ");
871         let ty_sig = default.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     text.push(';');
877     Ok(Signature { text, defs, refs })
878 }
879
880 fn make_assoc_const_signature(
881     id: NodeId,
882     ident: ast::Name,
883     ty: &ast::Ty,
884     default: Option<&ast::Expr>,
885     scx: &SaveContext,
886 ) -> Result {
887     let mut text = "const ".to_owned();
888     let name = ident.to_string();
889     let mut defs = vec![
890         SigElement {
891             id: id_from_node_id(id, scx),
892             start: text.len(),
893             end: text.len() + name.len(),
894         },
895     ];
896     let mut refs = vec![];
897     text.push_str(&name);
898     text.push_str(": ");
899
900     let ty_sig = ty.make(text.len(), Some(id), scx)?;
901     text.push_str(&ty_sig.text);
902     defs.extend(ty_sig.defs.into_iter());
903     refs.extend(ty_sig.refs.into_iter());
904
905     if let Some(default) = default {
906         text.push_str(" = ");
907         text.push_str(&pprust::expr_to_string(default));
908     }
909     text.push(';');
910     Ok(Signature { text, defs, refs })
911 }
912
913 fn make_method_signature(
914     id: NodeId,
915     ident: ast::Ident,
916     generics: &ast::Generics,
917     m: &ast::MethodSig,
918     scx: &SaveContext,
919 ) -> Result {
920     // FIXME code dup with function signature
921     let mut text = String::new();
922     if m.header.constness.node == ast::Constness::Const {
923         text.push_str("const ");
924     }
925     if m.header.asyncness.is_async() {
926         text.push_str("async ");
927     }
928     if m.header.unsafety == ast::Unsafety::Unsafe {
929         text.push_str("unsafe ");
930     }
931     if m.header.abi != ::rustc_target::spec::abi::Abi::Rust {
932         text.push_str("extern");
933         text.push_str(&m.header.abi.to_string());
934         text.push(' ');
935     }
936     text.push_str("fn ");
937
938     let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
939
940     sig.text.push('(');
941     for i in &m.decl.inputs {
942         // FIXME should descend into patterns to add defs.
943         sig.text.push_str(&pprust::pat_to_string(&i.pat));
944         sig.text.push_str(": ");
945         let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?;
946         sig.text.push_str(&nested.text);
947         sig.text.push(',');
948         sig.defs.extend(nested.defs.into_iter());
949         sig.refs.extend(nested.refs.into_iter());
950     }
951     sig.text.push(')');
952
953     if let ast::FunctionRetTy::Ty(ref t) = m.decl.output {
954         sig.text.push_str(" -> ");
955         let nested = t.make(sig.text.len(), None, scx)?;
956         sig.text.push_str(&nested.text);
957         sig.defs.extend(nested.defs.into_iter());
958         sig.refs.extend(nested.refs.into_iter());
959     }
960     sig.text.push_str(" {}");
961
962     Ok(sig)
963 }