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.
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.
11 use front::map::DefPathData;
12 use middle::cstore::LOCAL_CRATE;
13 use middle::def_id::DefId;
14 use middle::ty::{self, Ty, TyCtxt};
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
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);
27 /// Returns a string identifying this def-id. This string is
28 /// suitable for user output. It always begins with a crate identifier.
29 pub fn absolute_item_path_str(&self, def_id: DefId) -> String {
30 let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
31 self.push_item_path(&mut buffer, def_id);
35 /// Returns the "path" to a particular crate. This can proceed in
36 /// various ways, depending on the `root_mode` of the `buffer`.
37 /// (See `RootMode` enum for more details.)
38 pub fn push_krate_path<T>(&self, buffer: &mut T, cnum: ast::CrateNum)
39 where T: ItemPathBuffer
41 match *buffer.root_mode() {
43 // In local mode, when we encounter a crate other than
44 // LOCAL_CRATE, execution proceeds in one of two ways:
46 // 1. for a direct dependency, where user added an
47 // `extern crate` manually, we put the `extern
48 // crate` as the parent. So you wind up with
49 // something relative to the current crate.
50 // 2. for an indirect crate, where there is no extern
51 // crate, we just prepend the crate name.
53 // Returns `None` for the local crate.
54 if cnum != LOCAL_CRATE {
55 let opt_extern_crate = self.sess.cstore.extern_crate(cnum);
56 let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| {
57 if extern_crate.direct {
58 Some(extern_crate.def_id)
63 if let Some(extern_crate_def_id) = opt_extern_crate {
64 self.push_item_path(buffer, extern_crate_def_id);
66 buffer.push(&self.crate_name(cnum));
70 RootMode::Absolute => {
71 // In absolute mode, just write the crate name
73 buffer.push(&self.crate_name(cnum));
78 pub fn push_item_path<T>(&self, buffer: &mut T, def_id: DefId)
79 where T: ItemPathBuffer
81 let key = self.def_key(def_id);
82 match key.disambiguated_data.data {
83 DefPathData::CrateRoot => {
84 assert!(key.parent.is_none());
85 self.push_krate_path(buffer, def_id.krate);
88 DefPathData::InlinedRoot(ref root_path) => {
89 assert!(key.parent.is_none());
90 self.push_item_path(buffer, root_path.def_id);
93 DefPathData::Impl => {
94 self.push_impl_path(buffer, def_id);
97 // Unclear if there is any value in distinguishing these.
98 // Probably eventually (and maybe we would even want
99 // finer-grained distinctions, e.g. between enum/struct).
100 data @ DefPathData::Misc |
101 data @ DefPathData::TypeNs(..) |
102 data @ DefPathData::ValueNs(..) |
103 data @ DefPathData::TypeParam(..) |
104 data @ DefPathData::LifetimeDef(..) |
105 data @ DefPathData::EnumVariant(..) |
106 data @ DefPathData::Field(..) |
107 data @ DefPathData::StructCtor |
108 data @ DefPathData::Initializer |
109 data @ DefPathData::MacroDef(..) |
110 data @ DefPathData::ClosureExpr |
111 data @ DefPathData::Binding(..) => {
112 let parent_def_id = self.parent_def_id(def_id).unwrap();
113 self.push_item_path(buffer, parent_def_id);
114 buffer.push(&data.as_interned_str());
119 fn push_impl_path<T>(&self,
122 where T: ItemPathBuffer
124 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
126 let use_types = if !impl_def_id.is_local() {
127 // always have full types available for extern crates
130 // for local crates, check whether type info is
131 // available; typeck might not have completed yet
132 self.impl_trait_refs.borrow().contains_key(&impl_def_id)
136 return self.push_impl_path_fallback(buffer, impl_def_id);
139 // Decide whether to print the parent path for the impl.
140 // Logically, since impls are global, it's never needed, but
141 // users may find it useful. Currently, we omit the parent if
142 // the impl is either in the same module as the self-type or
144 let self_ty = self.lookup_item_type(impl_def_id).ty;
145 let in_self_mod = match self.characteristic_def_id_of_type(self_ty) {
147 Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
150 let impl_trait_ref = self.impl_trait_ref(impl_def_id);
151 let in_trait_mod = match impl_trait_ref {
153 Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
156 if !in_self_mod && !in_trait_mod {
157 // If the impl is not co-located with either self-type or
158 // trait-type, then fallback to a format that identifies
159 // the module more clearly.
160 self.push_item_path(buffer, parent_def_id);
161 if let Some(trait_ref) = impl_trait_ref {
162 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
164 buffer.push(&format!("<impl {}>", self_ty));
169 // Otherwise, try to give a good form that would be valid language
170 // syntax. Preferably using associated item notation.
172 if let Some(trait_ref) = impl_trait_ref {
174 buffer.push(&format!("<{} as {}>",
180 // Inherent impls. Try to print `Foo::bar` for an inherent
181 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
182 // anything other than a simple path.
184 ty::TyStruct(adt_def, substs) |
185 ty::TyEnum(adt_def, substs) => {
186 if substs.types.is_empty() { // ignore regions
187 self.push_item_path(buffer, adt_def.did);
189 buffer.push(&format!("<{}>", self_ty));
199 buffer.push(&format!("{}", self_ty));
203 buffer.push(&format!("<{}>", self_ty));
208 fn push_impl_path_fallback<T>(&self,
211 where T: ItemPathBuffer
213 // If no type info is available, fall back to
214 // pretty printing some span information. This should
215 // only occur very early in the compiler pipeline.
216 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
217 self.push_item_path(buffer, parent_def_id);
218 let node_id = self.map.as_local_node_id(impl_def_id).unwrap();
219 let item = self.map.expect_item(node_id);
220 let span_str = self.sess.codemap().span_to_string(item.span);
221 buffer.push(&format!("<impl at {}>", span_str));
224 /// As a heuristic, when we see an impl, if we see that the
225 /// 'self-type' is a type defined in the same module as the impl,
226 /// we can omit including the path to the impl itself. This
227 /// function tries to find a "characteristic def-id" for a
228 /// type. It's just a heuristic so it makes some questionable
229 /// decisions and we may want to adjust it later.
230 fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option<DefId> {
232 ty::TyStruct(adt_def, _) |
233 ty::TyEnum(adt_def, _) =>
236 ty::TyTrait(ref data) =>
237 Some(data.principal_def_id()),
240 self.characteristic_def_id_of_type(subty),
244 self.characteristic_def_id_of_type(mt.ty),
246 ty::TyTuple(ref tys) =>
248 .filter_map(|ty| self.characteristic_def_id_of_type(ty))
256 /// Returns the def-id of `def_id`'s parent in the def tree. If
257 /// this returns `None`, then `def_id` represents a crate root or
259 fn parent_def_id(&self, def_id: DefId) -> Option<DefId> {
260 let key = self.def_key(def_id);
261 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
265 /// Unifying Trait for different kinds of item paths we might
266 /// construct. The basic interface is that components get pushed: the
267 /// instance can also customize how we handle the root of a crate.
268 pub trait ItemPathBuffer {
269 fn root_mode(&self) -> &RootMode;
270 fn push(&mut self, text: &str);
275 /// Try to make a path relative to the local crate. In
276 /// particular, local paths have no prefix, and if the path comes
277 /// from an extern crate, start with the path to the `extern
278 /// crate` declaration.
281 /// Always prepend the crate name to the path, forming an absolute
282 /// path from within a given set of crates.
287 struct LocalPathBuffer {
292 impl LocalPathBuffer {
293 fn new(root_mode: RootMode) -> LocalPathBuffer {
295 root_mode: root_mode,
300 fn into_string(self) -> String {
306 impl ItemPathBuffer for LocalPathBuffer {
307 fn root_mode(&self) -> &RootMode {
311 fn push(&mut self, text: &str) {
312 if !self.str.is_empty() {
313 self.str.push_str("::");
315 self.str.push_str(text);