]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/debuginfo/type_names.rs
remove `get_ident` and `get_name`, make `as_str` sound
[rust.git] / src / librustc_trans / trans / debuginfo / type_names.rs
1 // Copyright 2015 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 // Type Names for Debug Info.
12
13 use super::namespace::crate_root_namespace;
14
15 use trans::common::CrateContext;
16 use middle::subst::{self, Substs};
17 use middle::ty::{self, Ty};
18
19 use syntax::ast;
20
21
22 // Compute the name of the type as it should be stored in debuginfo. Does not do
23 // any caching, i.e. calling the function twice with the same type will also do
24 // the work twice. The `qualified` parameter only affects the first level of the
25 // type name, further levels (i.e. type parameters) are always fully qualified.
26 pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
27                                              t: Ty<'tcx>,
28                                              qualified: bool)
29                                              -> String {
30     let mut result = String::with_capacity(64);
31     push_debuginfo_type_name(cx, t, qualified, &mut result);
32     result
33 }
34
35 // Pushes the name of the type as it should be stored in debuginfo on the
36 // `output` String. See also compute_debuginfo_type_name().
37 pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
38                                           t: Ty<'tcx>,
39                                           qualified: bool,
40                                           output: &mut String) {
41     match t.sty {
42         ty::TyBool              => output.push_str("bool"),
43         ty::TyChar              => output.push_str("char"),
44         ty::TyStr               => output.push_str("str"),
45         ty::TyInt(ast::TyIs)     => output.push_str("isize"),
46         ty::TyInt(ast::TyI8)    => output.push_str("i8"),
47         ty::TyInt(ast::TyI16)   => output.push_str("i16"),
48         ty::TyInt(ast::TyI32)   => output.push_str("i32"),
49         ty::TyInt(ast::TyI64)   => output.push_str("i64"),
50         ty::TyUint(ast::TyUs)    => output.push_str("usize"),
51         ty::TyUint(ast::TyU8)   => output.push_str("u8"),
52         ty::TyUint(ast::TyU16)  => output.push_str("u16"),
53         ty::TyUint(ast::TyU32)  => output.push_str("u32"),
54         ty::TyUint(ast::TyU64)  => output.push_str("u64"),
55         ty::TyFloat(ast::TyF32) => output.push_str("f32"),
56         ty::TyFloat(ast::TyF64) => output.push_str("f64"),
57         ty::TyStruct(def_id, substs) |
58         ty::TyEnum(def_id, substs) => {
59             push_item_name(cx, def_id, qualified, output);
60             push_type_params(cx, substs, output);
61         },
62         ty::TyTuple(ref component_types) => {
63             output.push('(');
64             for &component_type in component_types {
65                 push_debuginfo_type_name(cx, component_type, true, output);
66                 output.push_str(", ");
67             }
68             if !component_types.is_empty() {
69                 output.pop();
70                 output.pop();
71             }
72             output.push(')');
73         },
74         ty::TyBox(inner_type) => {
75             output.push_str("Box<");
76             push_debuginfo_type_name(cx, inner_type, true, output);
77             output.push('>');
78         },
79         ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
80             output.push('*');
81             match mutbl {
82                 ast::MutImmutable => output.push_str("const "),
83                 ast::MutMutable => output.push_str("mut "),
84             }
85
86             push_debuginfo_type_name(cx, inner_type, true, output);
87         },
88         ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
89             output.push('&');
90             if mutbl == ast::MutMutable {
91                 output.push_str("mut ");
92             }
93
94             push_debuginfo_type_name(cx, inner_type, true, output);
95         },
96         ty::TyArray(inner_type, len) => {
97             output.push('[');
98             push_debuginfo_type_name(cx, inner_type, true, output);
99             output.push_str(&format!("; {}", len));
100             output.push(']');
101         },
102         ty::TySlice(inner_type) => {
103             output.push('[');
104             push_debuginfo_type_name(cx, inner_type, true, output);
105             output.push(']');
106         },
107         ty::TyTrait(ref trait_data) => {
108             let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
109             push_item_name(cx, principal.def_id, false, output);
110             push_type_params(cx, principal.substs, output);
111         },
112         ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
113             if unsafety == ast::Unsafety::Unsafe {
114                 output.push_str("unsafe ");
115             }
116
117             if abi != ::syntax::abi::Rust {
118                 output.push_str("extern \"");
119                 output.push_str(abi.name());
120                 output.push_str("\" ");
121             }
122
123             output.push_str("fn(");
124
125             let sig = cx.tcx().erase_late_bound_regions(sig);
126             if !sig.inputs.is_empty() {
127                 for &parameter_type in &sig.inputs {
128                     push_debuginfo_type_name(cx, parameter_type, true, output);
129                     output.push_str(", ");
130                 }
131                 output.pop();
132                 output.pop();
133             }
134
135             if sig.variadic {
136                 if !sig.inputs.is_empty() {
137                     output.push_str(", ...");
138                 } else {
139                     output.push_str("...");
140                 }
141             }
142
143             output.push(')');
144
145             match sig.output {
146                 ty::FnConverging(result_type) if result_type.is_nil() => {}
147                 ty::FnConverging(result_type) => {
148                     output.push_str(" -> ");
149                     push_debuginfo_type_name(cx, result_type, true, output);
150                 }
151                 ty::FnDiverging => {
152                     output.push_str(" -> !");
153                 }
154             }
155         },
156         ty::TyClosure(..) => {
157             output.push_str("closure");
158         }
159         ty::TyError |
160         ty::TyInfer(_) |
161         ty::TyProjection(..) |
162         ty::TyParam(_) => {
163             cx.sess().bug(&format!("debuginfo: Trying to create type name for \
164                 unexpected type: {:?}", t));
165         }
166     }
167
168     fn push_item_name(cx: &CrateContext,
169                       def_id: ast::DefId,
170                       qualified: bool,
171                       output: &mut String) {
172         cx.tcx().with_path(def_id, |path| {
173             if qualified {
174                 if def_id.krate == ast::LOCAL_CRATE {
175                     output.push_str(crate_root_namespace(cx));
176                     output.push_str("::");
177                 }
178
179                 let mut path_element_count = 0;
180                 for path_element in path {
181                     output.push_str(&path_element.name().as_str());
182                     output.push_str("::");
183                     path_element_count += 1;
184                 }
185
186                 if path_element_count == 0 {
187                     cx.sess().bug("debuginfo: Encountered empty item path!");
188                 }
189
190                 output.pop();
191                 output.pop();
192             } else {
193                 let name = path.last().expect("debuginfo: Empty item path?").name();
194                 output.push_str(&name.as_str());
195             }
196         });
197     }
198
199     // Pushes the type parameters in the given `Substs` to the output string.
200     // This ignores region parameters, since they can't reliably be
201     // reconstructed for items from non-local crates. For local crates, this
202     // would be possible but with inlining and LTO we have to use the least
203     // common denominator - otherwise we would run into conflicts.
204     fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
205                                   substs: &subst::Substs<'tcx>,
206                                   output: &mut String) {
207         if substs.types.is_empty() {
208             return;
209         }
210
211         output.push('<');
212
213         for &type_parameter in &substs.types {
214             push_debuginfo_type_name(cx, type_parameter, true, output);
215             output.push_str(", ");
216         }
217
218         output.pop();
219         output.pop();
220
221         output.push('>');
222     }
223 }