]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/debuginfo/type_names.rs
Rollup merge of #55754 - spastorino:fix-process-output-docs, r=alexcrichton
[rust.git] / src / librustc_codegen_llvm / 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 common::CodegenCx;
14 use rustc::hir::def_id::DefId;
15 use rustc::ty::subst::Substs;
16 use rustc::ty::{self, Ty};
17
18 use rustc::hir;
19
20 // Compute the name of the type as it should be stored in debuginfo. Does not do
21 // any caching, i.e. calling the function twice with the same type will also do
22 // the work twice. The `qualified` parameter only affects the first level of the
23 // type name, further levels (i.e. type parameters) are always fully qualified.
24 pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
25                                              t: Ty<'tcx>,
26                                              qualified: bool)
27                                              -> String {
28     let mut result = String::with_capacity(64);
29     push_debuginfo_type_name(cx, t, qualified, &mut result);
30     result
31 }
32
33 // Pushes the name of the type as it should be stored in debuginfo on the
34 // `output` String. See also compute_debuginfo_type_name().
35 pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
36                                           t: Ty<'tcx>,
37                                           qualified: bool,
38                                           output: &mut String) {
39     // When targeting MSVC, emit C++ style type names for compatibility with
40     // .natvis visualizers (and perhaps other existing native debuggers?)
41     let cpp_like_names = cx.sess().target.target.options.is_like_msvc;
42
43     match t.sty {
44         ty::Bool => output.push_str("bool"),
45         ty::Char => output.push_str("char"),
46         ty::Str => output.push_str("str"),
47         ty::Never => output.push_str("!"),
48         ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()),
49         ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
50         ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
51         ty::Foreign(def_id) => push_item_name(cx, def_id, qualified, output),
52         ty::Adt(def, substs) => {
53             push_item_name(cx, def.did, qualified, output);
54             push_type_params(cx, substs, output);
55         },
56         ty::Tuple(component_types) => {
57             output.push('(');
58             for &component_type in component_types {
59                 push_debuginfo_type_name(cx, component_type, true, output);
60                 output.push_str(", ");
61             }
62             if !component_types.is_empty() {
63                 output.pop();
64                 output.pop();
65             }
66             output.push(')');
67         },
68         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
69             if !cpp_like_names {
70                 output.push('*');
71             }
72             match mutbl {
73                 hir::MutImmutable => output.push_str("const "),
74                 hir::MutMutable => output.push_str("mut "),
75             }
76
77             push_debuginfo_type_name(cx, inner_type, true, output);
78
79             if cpp_like_names {
80                 output.push('*');
81             }
82         },
83         ty::Ref(_, inner_type, mutbl) => {
84             if !cpp_like_names {
85                 output.push('&');
86             }
87             if mutbl == hir::MutMutable {
88                 output.push_str("mut ");
89             }
90
91             push_debuginfo_type_name(cx, inner_type, true, output);
92
93             if cpp_like_names {
94                 output.push('*');
95             }
96         },
97         ty::Array(inner_type, len) => {
98             output.push('[');
99             push_debuginfo_type_name(cx, inner_type, true, output);
100             output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
101             output.push(']');
102         },
103         ty::Slice(inner_type) => {
104             if cpp_like_names {
105                 output.push_str("slice<");
106             } else {
107                 output.push('[');
108             }
109
110             push_debuginfo_type_name(cx, inner_type, true, output);
111
112             if cpp_like_names {
113                 output.push('>');
114             } else {
115                 output.push(']');
116             }
117         },
118         ty::Dynamic(ref trait_data, ..) => {
119             let principal = cx.tcx.normalize_erasing_late_bound_regions(
120                 ty::ParamEnv::reveal_all(),
121                 &trait_data.principal(),
122             );
123             push_item_name(cx, principal.def_id, false, output);
124             push_type_params(cx, principal.substs, output);
125         },
126         ty::FnDef(..) | ty::FnPtr(_) => {
127             let sig = t.fn_sig(cx.tcx);
128             if sig.unsafety() == hir::Unsafety::Unsafe {
129                 output.push_str("unsafe ");
130             }
131
132             let abi = sig.abi();
133             if abi != ::abi::Abi::Rust {
134                 output.push_str("extern \"");
135                 output.push_str(abi.name());
136                 output.push_str("\" ");
137             }
138
139             output.push_str("fn(");
140
141             let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
142             if !sig.inputs().is_empty() {
143                 for &parameter_type in sig.inputs() {
144                     push_debuginfo_type_name(cx, parameter_type, true, output);
145                     output.push_str(", ");
146                 }
147                 output.pop();
148                 output.pop();
149             }
150
151             if sig.variadic {
152                 if !sig.inputs().is_empty() {
153                     output.push_str(", ...");
154                 } else {
155                     output.push_str("...");
156                 }
157             }
158
159             output.push(')');
160
161             if !sig.output().is_unit() {
162                 output.push_str(" -> ");
163                 push_debuginfo_type_name(cx, sig.output(), true, output);
164             }
165         },
166         ty::Closure(..) => {
167             output.push_str("closure");
168         }
169         ty::Generator(..) => {
170             output.push_str("generator");
171         }
172         ty::Error |
173         ty::Infer(_) |
174         ty::UnnormalizedProjection(..) |
175         ty::Projection(..) |
176         ty::Bound(..) |
177         ty::Opaque(..) |
178         ty::GeneratorWitness(..) |
179         ty::Param(_) => {
180             bug!("debuginfo: Trying to create type name for \
181                   unexpected type: {:?}", t);
182         }
183     }
184
185     fn push_item_name(cx: &CodegenCx,
186                       def_id: DefId,
187                       qualified: bool,
188                       output: &mut String) {
189         if qualified {
190             output.push_str(&cx.tcx.crate_name(def_id.krate).as_str());
191             for path_element in cx.tcx.def_path(def_id).data {
192                 output.push_str("::");
193                 output.push_str(&path_element.data.as_interned_str().as_str());
194             }
195         } else {
196             output.push_str(&cx.tcx.item_name(def_id).as_str());
197         }
198     }
199
200     // Pushes the type parameters in the given `Substs` to the output string.
201     // This ignores region parameters, since they can't reliably be
202     // reconstructed for items from non-local crates. For local crates, this
203     // would be possible but with inlining and LTO we have to use the least
204     // common denominator - otherwise we would run into conflicts.
205     fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
206                                   substs: &Substs<'tcx>,
207                                   output: &mut String) {
208         if substs.types().next().is_none() {
209             return;
210         }
211
212         output.push('<');
213
214         for type_parameter in substs.types() {
215             push_debuginfo_type_name(cx, type_parameter, true, output);
216             output.push_str(", ");
217         }
218
219         output.pop();
220         output.pop();
221
222         output.push('>');
223     }
224 }