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