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