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