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