]> git.proxmox.com Git - rustc.git/blob - src/librustc/ty/item_path.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc / ty / item_path.rs
1 // Copyright 2012-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 use hir::map::DefPathData;
12 use middle::cstore::LOCAL_CRATE;
13 use hir::def_id::{DefId, CRATE_DEF_INDEX};
14 use ty::{self, Ty, TyCtxt};
15 use syntax::ast;
16
17 impl<'tcx> TyCtxt<'tcx> {
18 /// Returns a string identifying this def-id. This string is
19 /// suitable for user output. It is relative to the current crate
20 /// root.
21 pub fn item_path_str(&self, def_id: DefId) -> String {
22 let mut buffer = LocalPathBuffer::new(RootMode::Local);
23 self.push_item_path(&mut buffer, def_id);
24 buffer.into_string()
25 }
26
27 /// Returns a string identifying this local node-id.
28 pub fn node_path_str(&self, id: ast::NodeId) -> String {
29 self.item_path_str(self.map.local_def_id(id))
30 }
31
32 /// Returns a string identifying this def-id. This string is
33 /// suitable for user output. It always begins with a crate identifier.
34 pub fn absolute_item_path_str(&self, def_id: DefId) -> String {
35 let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
36 self.push_item_path(&mut buffer, def_id);
37 buffer.into_string()
38 }
39
40 /// Returns the "path" to a particular crate. This can proceed in
41 /// various ways, depending on the `root_mode` of the `buffer`.
42 /// (See `RootMode` enum for more details.)
43 pub fn push_krate_path<T>(&self, buffer: &mut T, cnum: ast::CrateNum)
44 where T: ItemPathBuffer
45 {
46 match *buffer.root_mode() {
47 RootMode::Local => {
48 // In local mode, when we encounter a crate other than
49 // LOCAL_CRATE, execution proceeds in one of two ways:
50 //
51 // 1. for a direct dependency, where user added an
52 // `extern crate` manually, we put the `extern
53 // crate` as the parent. So you wind up with
54 // something relative to the current crate.
55 // 2. for an indirect crate, where there is no extern
56 // crate, we just prepend the crate name.
57 //
58 // Returns `None` for the local crate.
59 if cnum != LOCAL_CRATE {
60 let opt_extern_crate = self.sess.cstore.extern_crate(cnum);
61 let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| {
62 if extern_crate.direct {
63 Some(extern_crate.def_id)
64 } else {
65 None
66 }
67 });
68 if let Some(extern_crate_def_id) = opt_extern_crate {
69 self.push_item_path(buffer, extern_crate_def_id);
70 } else {
71 buffer.push(&self.crate_name(cnum));
72 }
73 }
74 }
75 RootMode::Absolute => {
76 // In absolute mode, just write the crate name
77 // unconditionally.
78 buffer.push(&self.crate_name(cnum));
79 }
80 }
81 }
82
83 /// If possible, this pushes a global path resolving to `external_def_id` that is visible
84 /// from at least one local module and returns true. If the crate defining `external_def_id` is
85 /// declared with an `extern crate`, the path is guarenteed to use the `extern crate`.
86 pub fn try_push_visible_item_path<T>(&self, buffer: &mut T, external_def_id: DefId) -> bool
87 where T: ItemPathBuffer
88 {
89 let visible_parent_map = self.sess.cstore.visible_parent_map();
90
91 let (mut cur_def, mut cur_path) = (external_def_id, Vec::<ast::Name>::new());
92 loop {
93 // If `cur_def` is a direct or injected extern crate, push the path to the crate
94 // followed by the path to the item within the crate and return.
95 if cur_def.index == CRATE_DEF_INDEX {
96 match self.sess.cstore.extern_crate(cur_def.krate) {
97 Some(extern_crate) if extern_crate.direct => {
98 self.push_item_path(buffer, extern_crate.def_id);
99 cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
100 return true;
101 }
102 None => {
103 buffer.push(&self.crate_name(cur_def.krate));
104 cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
105 return true;
106 }
107 _ => {},
108 }
109 }
110
111 cur_path.push(self.sess.cstore.item_name(cur_def));
112 match visible_parent_map.get(&cur_def) {
113 Some(&def) => cur_def = def,
114 None => return false,
115 };
116 }
117 }
118
119 pub fn push_item_path<T>(&self, buffer: &mut T, def_id: DefId)
120 where T: ItemPathBuffer
121 {
122 match *buffer.root_mode() {
123 RootMode::Local if !def_id.is_local() =>
124 if self.try_push_visible_item_path(buffer, def_id) { return },
125 _ => {}
126 }
127
128 let key = self.def_key(def_id);
129 match key.disambiguated_data.data {
130 DefPathData::CrateRoot => {
131 assert!(key.parent.is_none());
132 self.push_krate_path(buffer, def_id.krate);
133 }
134
135 DefPathData::InlinedRoot(ref root_path) => {
136 assert!(key.parent.is_none());
137 self.push_item_path(buffer, root_path.def_id);
138 }
139
140 DefPathData::Impl => {
141 self.push_impl_path(buffer, def_id);
142 }
143
144 // Unclear if there is any value in distinguishing these.
145 // Probably eventually (and maybe we would even want
146 // finer-grained distinctions, e.g. between enum/struct).
147 data @ DefPathData::Misc |
148 data @ DefPathData::TypeNs(..) |
149 data @ DefPathData::ValueNs(..) |
150 data @ DefPathData::TypeParam(..) |
151 data @ DefPathData::LifetimeDef(..) |
152 data @ DefPathData::EnumVariant(..) |
153 data @ DefPathData::Field(..) |
154 data @ DefPathData::StructCtor |
155 data @ DefPathData::Initializer |
156 data @ DefPathData::MacroDef(..) |
157 data @ DefPathData::ClosureExpr |
158 data @ DefPathData::Binding(..) => {
159 let parent_def_id = self.parent_def_id(def_id).unwrap();
160 self.push_item_path(buffer, parent_def_id);
161 buffer.push(&data.as_interned_str());
162 }
163 }
164 }
165
166 fn push_impl_path<T>(&self,
167 buffer: &mut T,
168 impl_def_id: DefId)
169 where T: ItemPathBuffer
170 {
171 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
172
173 let use_types = if !impl_def_id.is_local() {
174 // always have full types available for extern crates
175 true
176 } else {
177 // for local crates, check whether type info is
178 // available; typeck might not have completed yet
179 self.impl_trait_refs.borrow().contains_key(&impl_def_id)
180 };
181
182 if !use_types {
183 return self.push_impl_path_fallback(buffer, impl_def_id);
184 }
185
186 // Decide whether to print the parent path for the impl.
187 // Logically, since impls are global, it's never needed, but
188 // users may find it useful. Currently, we omit the parent if
189 // the impl is either in the same module as the self-type or
190 // as the trait.
191 let self_ty = self.lookup_item_type(impl_def_id).ty;
192 let in_self_mod = match self.characteristic_def_id_of_type(self_ty) {
193 None => false,
194 Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
195 };
196
197 let impl_trait_ref = self.impl_trait_ref(impl_def_id);
198 let in_trait_mod = match impl_trait_ref {
199 None => false,
200 Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
201 };
202
203 if !in_self_mod && !in_trait_mod {
204 // If the impl is not co-located with either self-type or
205 // trait-type, then fallback to a format that identifies
206 // the module more clearly.
207 self.push_item_path(buffer, parent_def_id);
208 if let Some(trait_ref) = impl_trait_ref {
209 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
210 } else {
211 buffer.push(&format!("<impl {}>", self_ty));
212 }
213 return;
214 }
215
216 // Otherwise, try to give a good form that would be valid language
217 // syntax. Preferably using associated item notation.
218
219 if let Some(trait_ref) = impl_trait_ref {
220 // Trait impls.
221 buffer.push(&format!("<{} as {}>",
222 self_ty,
223 trait_ref));
224 return;
225 }
226
227 // Inherent impls. Try to print `Foo::bar` for an inherent
228 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
229 // anything other than a simple path.
230 match self_ty.sty {
231 ty::TyStruct(adt_def, substs) |
232 ty::TyEnum(adt_def, substs) => {
233 if substs.types.is_empty() { // ignore regions
234 self.push_item_path(buffer, adt_def.did);
235 } else {
236 buffer.push(&format!("<{}>", self_ty));
237 }
238 }
239
240 ty::TyBool |
241 ty::TyChar |
242 ty::TyInt(_) |
243 ty::TyUint(_) |
244 ty::TyFloat(_) |
245 ty::TyStr => {
246 buffer.push(&format!("{}", self_ty));
247 }
248
249 _ => {
250 buffer.push(&format!("<{}>", self_ty));
251 }
252 }
253 }
254
255 fn push_impl_path_fallback<T>(&self,
256 buffer: &mut T,
257 impl_def_id: DefId)
258 where T: ItemPathBuffer
259 {
260 // If no type info is available, fall back to
261 // pretty printing some span information. This should
262 // only occur very early in the compiler pipeline.
263 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
264 self.push_item_path(buffer, parent_def_id);
265 let node_id = self.map.as_local_node_id(impl_def_id).unwrap();
266 let item = self.map.expect_item(node_id);
267 let span_str = self.sess.codemap().span_to_string(item.span);
268 buffer.push(&format!("<impl at {}>", span_str));
269 }
270
271 /// As a heuristic, when we see an impl, if we see that the
272 /// 'self-type' is a type defined in the same module as the impl,
273 /// we can omit including the path to the impl itself. This
274 /// function tries to find a "characteristic def-id" for a
275 /// type. It's just a heuristic so it makes some questionable
276 /// decisions and we may want to adjust it later.
277 fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option<DefId> {
278 match ty.sty {
279 ty::TyStruct(adt_def, _) |
280 ty::TyEnum(adt_def, _) =>
281 Some(adt_def.did),
282
283 ty::TyTrait(ref data) =>
284 Some(data.principal_def_id()),
285
286 ty::TyBox(subty) =>
287 self.characteristic_def_id_of_type(subty),
288
289 ty::TyRawPtr(mt) |
290 ty::TyRef(_, mt) =>
291 self.characteristic_def_id_of_type(mt.ty),
292
293 ty::TyTuple(ref tys) =>
294 tys.iter()
295 .filter_map(|ty| self.characteristic_def_id_of_type(ty))
296 .next(),
297
298 _ =>
299 None
300 }
301 }
302
303 /// Returns the def-id of `def_id`'s parent in the def tree. If
304 /// this returns `None`, then `def_id` represents a crate root or
305 /// inlined root.
306 fn parent_def_id(&self, def_id: DefId) -> Option<DefId> {
307 let key = self.def_key(def_id);
308 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
309 }
310 }
311
312 /// Unifying Trait for different kinds of item paths we might
313 /// construct. The basic interface is that components get pushed: the
314 /// instance can also customize how we handle the root of a crate.
315 pub trait ItemPathBuffer {
316 fn root_mode(&self) -> &RootMode;
317 fn push(&mut self, text: &str);
318 }
319
320 #[derive(Debug)]
321 pub enum RootMode {
322 /// Try to make a path relative to the local crate. In
323 /// particular, local paths have no prefix, and if the path comes
324 /// from an extern crate, start with the path to the `extern
325 /// crate` declaration.
326 Local,
327
328 /// Always prepend the crate name to the path, forming an absolute
329 /// path from within a given set of crates.
330 Absolute,
331 }
332
333 #[derive(Debug)]
334 struct LocalPathBuffer {
335 root_mode: RootMode,
336 str: String,
337 }
338
339 impl LocalPathBuffer {
340 fn new(root_mode: RootMode) -> LocalPathBuffer {
341 LocalPathBuffer {
342 root_mode: root_mode,
343 str: String::new()
344 }
345 }
346
347 fn into_string(self) -> String {
348 self.str
349 }
350
351 }
352
353 impl ItemPathBuffer for LocalPathBuffer {
354 fn root_mode(&self) -> &RootMode {
355 &self.root_mode
356 }
357
358 fn push(&mut self, text: &str) {
359 if !self.str.is_empty() {
360 self.str.push_str("::");
361 }
362 self.str.push_str(text);
363 }
364 }