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.
12 use ast
::{MetaItem, Expr,}
;
14 use ext
::base
::{ExtCtxt, Annotatable}
;
15 use ext
::build
::AstBuilder
;
16 use ext
::deriving
::generic
::*;
17 use ext
::deriving
::generic
::ty
::*;
21 pub fn expand_deriving_show(cx
: &mut ExtCtxt
,
25 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
::MutMutable
));
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(),
40 generics
: LifetimeBounds
::empty(),
41 explicit_self
: borrowed_explicit_self(),
43 ret_ty
: Literal(path_std
!(cx
, core
::fmt
::Result
)),
44 attributes
: Vec
::new(),
46 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
47 show_substructure(a
, b
, c
)
51 associated_types
: Vec
::new(),
53 trait_def
.expand(cx
, mitem
, item
, push
)
56 /// We use the debug builders to do the heavy lifting here
57 fn show_substructure(cx
: &mut ExtCtxt
, span
: Span
,
58 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
= match *substr
.fields
{
63 Struct(_
) => substr
.type_ident
,
64 EnumMatching(_
, v
, _
) => v
.node
.name
,
65 EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
66 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
, ast
::Lit_
::LitStr(ident
.name
.as_str(),
73 ast
::StrStyle
::CookedStr
));
74 let mut expr
= substr
.nonself_args
[0].clone();
76 match *substr
.fields
{
77 Struct(ref fields
) | EnumMatching(_
, _
, ref fields
) => {
79 if fields
.is_empty() || fields
[0].name
.is_none() {
80 // tuple struct/"normal" variant
81 expr
= cx
.expr_method_call(span
,
83 token
::str_to_ident("debug_tuple"),
87 // Use double indirection to make sure this works for unsized types
88 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
89 let field
= cx
.expr_addr_of(field
.span
, field
);
91 expr
= cx
.expr_method_call(span
,
93 token
::str_to_ident("field"),
97 // normal struct/struct variant
98 expr
= cx
.expr_method_call(span
,
100 token
::str_to_ident("debug_struct"),
103 for field
in fields
{
104 let name
= cx
.expr_lit(field
.span
, ast
::Lit_
::LitStr(
105 field
.name
.unwrap().name
.as_str(),
106 ast
::StrStyle
::CookedStr
));
108 // Use double indirection to make sure this works for unsized types
109 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
110 let field
= cx
.expr_addr_of(field
.span
, field
);
111 expr
= cx
.expr_method_call(span
,
113 token
::str_to_ident("field"),
121 cx
.expr_method_call(span
,
123 token
::str_to_ident("finish"),