]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | ||
ff7c6d11 | 11 | use deriving::path_std; |
9cc50fc6 SL |
12 | use deriving::generic::*; |
13 | use deriving::generic::ty::*; | |
14 | ||
476ff2be | 15 | use syntax::ast::{self, Ident}; |
5bcae85e SL |
16 | use syntax::ast::{Expr, MetaItem}; |
17 | use syntax::ext::base::{Annotatable, ExtCtxt}; | |
9cc50fc6 | 18 | use syntax::ext::build::AstBuilder; |
9cc50fc6 | 19 | use syntax::ptr::P; |
5bcae85e | 20 | use syntax_pos::{DUMMY_SP, Span}; |
1a4d82fc | 21 | |
b039eaaf | 22 | pub fn expand_deriving_debug(cx: &mut ExtCtxt, |
5bcae85e SL |
23 | span: Span, |
24 | mitem: &MetaItem, | |
25 | item: &Annotatable, | |
26 | push: &mut FnMut(Annotatable)) { | |
1a4d82fc | 27 | // &mut ::std::fmt::Formatter |
ff7c6d11 | 28 | let fmtr = Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), |
7453a54e | 29 | Borrowed(None, ast::Mutability::Mutable)); |
1a4d82fc JJ |
30 | |
31 | let trait_def = TraitDef { | |
3b2f2976 | 32 | span, |
1a4d82fc | 33 | attributes: Vec::new(), |
ff7c6d11 | 34 | path: path_std!(cx, fmt::Debug), |
1a4d82fc JJ |
35 | additional_bounds: Vec::new(), |
36 | generics: LifetimeBounds::empty(), | |
e9174d1e | 37 | is_unsafe: false, |
9e0c209e | 38 | supports_unions: false, |
5bcae85e SL |
39 | methods: vec![MethodDef { |
40 | name: "fmt", | |
41 | generics: LifetimeBounds::empty(), | |
42 | explicit_self: borrowed_explicit_self(), | |
83c7162d | 43 | args: vec![(fmtr, "f")], |
ff7c6d11 | 44 | ret_ty: Literal(path_std!(cx, fmt::Result)), |
5bcae85e SL |
45 | attributes: Vec::new(), |
46 | is_unsafe: false, | |
47 | unify_fieldless_variants: false, | |
48 | combine_substructure: combine_substructure(Box::new(|a, b, c| { | |
49 | show_substructure(a, b, c) | |
50 | })), | |
51 | }], | |
85aaf69f | 52 | associated_types: Vec::new(), |
1a4d82fc | 53 | }; |
62682a34 | 54 | trait_def.expand(cx, mitem, item, push) |
1a4d82fc JJ |
55 | } |
56 | ||
c34b1796 | 57 | /// We use the debug builders to do the heavy lifting here |
5bcae85e | 58 | fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { |
c34b1796 AL |
59 | // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() |
60 | // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() | |
61 | // based on the "shape". | |
7453a54e SL |
62 | let (ident, is_struct) = match *substr.fields { |
63 | Struct(vdata, _) => (substr.type_ident, vdata.is_struct()), | |
83c7162d | 64 | EnumMatching(_, _, v, _) => (v.node.ident, v.node.data.is_struct()), |
5bcae85e SL |
65 | EnumNonMatchingCollapsed(..) | |
66 | StaticStruct(..) | | |
67 | StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), | |
1a4d82fc JJ |
68 | }; |
69 | ||
cc61c64b | 70 | // We want to make sure we have the ctxt set so that we can use unstable methods |
ea8adc8c | 71 | let span = span.with_ctxt(cx.backtrace()); |
476ff2be | 72 | let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); |
83c7162d | 73 | let builder = Ident::from_str("debug_trait_builder").gensym(); |
92a42be0 | 74 | let builder_expr = cx.expr_ident(span, builder.clone()); |
1a4d82fc | 75 | |
92a42be0 | 76 | let fmt = substr.nonself_args[0].clone(); |
62682a34 | 77 | |
3157f602 | 78 | let mut stmts = match *substr.fields { |
5bcae85e | 79 | Struct(_, ref fields) | |
9e0c209e | 80 | EnumMatching(.., ref fields) => { |
92a42be0 | 81 | let mut stmts = vec![]; |
7453a54e | 82 | if !is_struct { |
1a4d82fc | 83 | // tuple struct/"normal" variant |
5bcae85e | 84 | let expr = |
476ff2be | 85 | cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]); |
7453a54e | 86 | stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); |
c34b1796 AL |
87 | |
88 | for field in fields { | |
62682a34 SL |
89 | // Use double indirection to make sure this works for unsized types |
90 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
91 | let field = cx.expr_addr_of(field.span, field); | |
92 | ||
92a42be0 SL |
93 | let expr = cx.expr_method_call(span, |
94 | builder_expr.clone(), | |
476ff2be | 95 | Ident::from_str("field"), |
92a42be0 SL |
96 | vec![field]); |
97 | ||
98 | // Use `let _ = expr;` to avoid triggering the | |
99 | // unused_results lint. | |
100 | stmts.push(stmt_let_undescore(cx, span, expr)); | |
1a4d82fc | 101 | } |
1a4d82fc JJ |
102 | } else { |
103 | // normal struct/struct variant | |
5bcae85e | 104 | let expr = |
476ff2be | 105 | cx.expr_method_call(span, fmt, Ident::from_str("debug_struct"), vec![name]); |
7453a54e | 106 | stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); |
c34b1796 AL |
107 | |
108 | for field in fields { | |
5bcae85e | 109 | let name = cx.expr_lit(field.span, |
476ff2be | 110 | ast::LitKind::Str(field.name.unwrap().name, |
5bcae85e | 111 | ast::StrStyle::Cooked)); |
62682a34 SL |
112 | |
113 | // Use double indirection to make sure this works for unsized types | |
114 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
115 | let field = cx.expr_addr_of(field.span, field); | |
92a42be0 SL |
116 | let expr = cx.expr_method_call(span, |
117 | builder_expr.clone(), | |
476ff2be | 118 | Ident::from_str("field"), |
92a42be0 SL |
119 | vec![name, field]); |
120 | stmts.push(stmt_let_undescore(cx, span, expr)); | |
1a4d82fc | 121 | } |
1a4d82fc | 122 | } |
92a42be0 | 123 | stmts |
1a4d82fc | 124 | } |
5bcae85e | 125 | _ => unreachable!(), |
92a42be0 SL |
126 | }; |
127 | ||
476ff2be | 128 | let expr = cx.expr_method_call(span, builder_expr, Ident::from_str("finish"), vec![]); |
92a42be0 | 129 | |
3157f602 XL |
130 | stmts.push(cx.stmt_expr(expr)); |
131 | let block = cx.block(span, stmts); | |
92a42be0 SL |
132 | cx.expr_block(block) |
133 | } | |
1a4d82fc | 134 | |
5bcae85e | 135 | fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P<ast::Expr>) -> ast::Stmt { |
92a42be0 SL |
136 | let local = P(ast::Local { |
137 | pat: cx.pat_wild(sp), | |
138 | ty: None, | |
139 | init: Some(expr), | |
140 | id: ast::DUMMY_NODE_ID, | |
141 | span: sp, | |
3157f602 | 142 | attrs: ast::ThinVec::new(), |
92a42be0 | 143 | }); |
3157f602 XL |
144 | ast::Stmt { |
145 | id: ast::DUMMY_NODE_ID, | |
146 | node: ast::StmtKind::Local(local), | |
147 | span: sp, | |
148 | } | |
1a4d82fc | 149 | } |