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.
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.
11 use deriving
::generic
::*;
12 use deriving
::generic
::ty
::*;
15 use syntax
::ast
::{Expr, MetaItem}
;
16 use syntax
::ext
::base
::{Annotatable, ExtCtxt}
;
17 use syntax
::ext
::build
::AstBuilder
;
18 use syntax
::parse
::token
;
20 use syntax_pos
::{DUMMY_SP, Span}
;
22 pub fn expand_deriving_debug(cx
: &mut ExtCtxt
,
26 push
: &mut FnMut(Annotatable
)) {
27 // &mut ::std::fmt::Formatter
28 let fmtr
= Ptr(Box
::new(Literal(path_std
!(cx
, core
::fmt
::Formatter
))),
29 Borrowed(None
, ast
::Mutability
::Mutable
));
31 let trait_def
= TraitDef
{
33 attributes
: Vec
::new(),
34 path
: path_std
!(cx
, core
::fmt
::Debug
),
35 additional_bounds
: Vec
::new(),
36 generics
: LifetimeBounds
::empty(),
38 supports_unions
: false,
39 methods
: vec
![MethodDef
{
41 generics
: LifetimeBounds
::empty(),
42 explicit_self
: borrowed_explicit_self(),
44 ret_ty
: Literal(path_std
!(cx
, core
::fmt
::Result
)),
45 attributes
: Vec
::new(),
47 unify_fieldless_variants
: false,
48 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
49 show_substructure(a
, b
, c
)
52 associated_types
: Vec
::new(),
54 trait_def
.expand(cx
, mitem
, item
, push
)
57 /// We use the debug builders to do the heavy lifting here
58 fn show_substructure(cx
: &mut ExtCtxt
, span
: Span
, substr
: &Substructure
) -> P
<Expr
> {
59 // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
60 // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
61 // based on the "shape".
62 let (ident
, is_struct
) = match *substr
.fields
{
63 Struct(vdata
, _
) => (substr
.type_ident
, vdata
.is_struct()),
64 EnumMatching(_
, v
, _
) => (v
.node
.name
, v
.node
.data
.is_struct()),
65 EnumNonMatchingCollapsed(..) |
67 StaticEnum(..) => cx
.span_bug(span
, "nonsensical .fields in `#[derive(Debug)]`"),
70 // We want to make sure we have the expn_id set so that we can use unstable methods
71 let span
= Span { expn_id: cx.backtrace(), ..span }
;
72 let name
= cx
.expr_lit(span
,
73 ast
::LitKind
::Str(ident
.name
.as_str(), ast
::StrStyle
::Cooked
));
74 let builder
= token
::str_to_ident("builder");
75 let builder_expr
= cx
.expr_ident(span
, builder
.clone());
77 let fmt
= substr
.nonself_args
[0].clone();
79 let mut stmts
= match *substr
.fields
{
80 Struct(_
, ref fields
) |
81 EnumMatching(.., ref fields
) => {
82 let mut stmts
= vec
![];
84 // tuple struct/"normal" variant
86 cx
.expr_method_call(span
, fmt
, token
::str_to_ident("debug_tuple"), vec
![name
]);
87 stmts
.push(cx
.stmt_let(DUMMY_SP
, true, builder
, expr
));
90 // Use double indirection to make sure this works for unsized types
91 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
92 let field
= cx
.expr_addr_of(field
.span
, field
);
94 let expr
= cx
.expr_method_call(span
,
96 token
::str_to_ident("field"),
99 // Use `let _ = expr;` to avoid triggering the
100 // unused_results lint.
101 stmts
.push(stmt_let_undescore(cx
, span
, expr
));
104 // normal struct/struct variant
106 cx
.expr_method_call(span
, fmt
, token
::str_to_ident("debug_struct"), vec
![name
]);
107 stmts
.push(cx
.stmt_let(DUMMY_SP
, true, builder
, expr
));
109 for field
in fields
{
110 let name
= cx
.expr_lit(field
.span
,
111 ast
::LitKind
::Str(field
.name
.unwrap().name
.as_str(),
112 ast
::StrStyle
::Cooked
));
114 // Use double indirection to make sure this works for unsized types
115 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
116 let field
= cx
.expr_addr_of(field
.span
, field
);
117 let expr
= cx
.expr_method_call(span
,
118 builder_expr
.clone(),
119 token
::str_to_ident("field"),
121 stmts
.push(stmt_let_undescore(cx
, span
, expr
));
129 let expr
= cx
.expr_method_call(span
, builder_expr
, token
::str_to_ident("finish"), vec
![]);
131 stmts
.push(cx
.stmt_expr(expr
));
132 let block
= cx
.block(span
, stmts
);
136 fn stmt_let_undescore(cx
: &mut ExtCtxt
, sp
: Span
, expr
: P
<ast
::Expr
>) -> ast
::Stmt
{
137 let local
= P(ast
::Local
{
138 pat
: cx
.pat_wild(sp
),
141 id
: ast
::DUMMY_NODE_ID
,
143 attrs
: ast
::ThinVec
::new(),
146 id
: ast
::DUMMY_NODE_ID
,
147 node
: ast
::StmtKind
::Local(local
),