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 hir
::map
::DefPathData
;
12 use middle
::cstore
::LOCAL_CRATE
;
13 use hir
::def_id
::{DefId, CRATE_DEF_INDEX}
;
14 use 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 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
))
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
);
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
46 match *buffer
.root_mode() {
48 // In local mode, when we encounter a crate other than
49 // LOCAL_CRATE, execution proceeds in one of two ways:
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.
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
)
68 if let Some(extern_crate_def_id
) = opt_extern_crate
{
69 self.push_item_path(buffer
, extern_crate_def_id
);
71 buffer
.push(&self.crate_name(cnum
));
75 RootMode
::Absolute
=> {
76 // In absolute mode, just write the crate name
78 buffer
.push(&self.crate_name(cnum
));
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
89 let visible_parent_map
= self.sess
.cstore
.visible_parent_map();
91 let (mut cur_def
, mut cur_path
) = (external_def_id
, Vec
::<ast
::Name
>::new());
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();
103 buffer
.push(&self.crate_name(cur_def
.krate
));
104 cur_path
.iter().rev().map(|segment
| buffer
.push(&segment
.as_str())).count();
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,
119 pub fn push_item_path
<T
>(&self, buffer
: &mut T
, def_id
: DefId
)
120 where T
: ItemPathBuffer
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 }
,
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
);
135 DefPathData
::InlinedRoot(ref root_path
) => {
136 assert
!(key
.parent
.is_none());
137 self.push_item_path(buffer
, root_path
.def_id
);
140 DefPathData
::Impl
=> {
141 self.push_impl_path(buffer
, def_id
);
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());
166 fn push_impl_path
<T
>(&self,
169 where T
: ItemPathBuffer
171 let parent_def_id
= self.parent_def_id(impl_def_id
).unwrap();
173 let use_types
= if !impl_def_id
.is_local() {
174 // always have full types available for extern crates
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
)
183 return self.push_impl_path_fallback(buffer
, impl_def_id
);
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
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
) {
194 Some(ty_def_id
) => self.parent_def_id(ty_def_id
) == Some(parent_def_id
),
197 let impl_trait_ref
= self.impl_trait_ref(impl_def_id
);
198 let in_trait_mod
= match impl_trait_ref
{
200 Some(trait_ref
) => self.parent_def_id(trait_ref
.def_id
) == Some(parent_def_id
),
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
));
211 buffer
.push(&format
!("<impl {}>", self_ty
));
216 // Otherwise, try to give a good form that would be valid language
217 // syntax. Preferably using associated item notation.
219 if let Some(trait_ref
) = impl_trait_ref
{
221 buffer
.push(&format
!("<{} as {}>",
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.
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
);
236 buffer
.push(&format
!("<{}>", self_ty
));
246 buffer
.push(&format
!("{}", self_ty
));
250 buffer
.push(&format
!("<{}>", self_ty
));
255 fn push_impl_path_fallback
<T
>(&self,
258 where T
: ItemPathBuffer
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
));
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
> {
279 ty
::TyStruct(adt_def
, _
) |
280 ty
::TyEnum(adt_def
, _
) =>
283 ty
::TyTrait(ref data
) =>
284 Some(data
.principal_def_id()),
287 self.characteristic_def_id_of_type(subty
),
291 self.characteristic_def_id_of_type(mt
.ty
),
293 ty
::TyTuple(ref tys
) =>
295 .filter_map(|ty
| self.characteristic_def_id_of_type(ty
))
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
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 }
)
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);
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.
328 /// Always prepend the crate name to the path, forming an absolute
329 /// path from within a given set of crates.
334 struct LocalPathBuffer
{
339 impl LocalPathBuffer
{
340 fn new(root_mode
: RootMode
) -> LocalPathBuffer
{
342 root_mode
: root_mode
,
347 fn into_string(self) -> String
{
353 impl ItemPathBuffer
for LocalPathBuffer
{
354 fn root_mode(&self) -> &RootMode
{
358 fn push(&mut self, text
: &str) {
359 if !self.str.is_empty() {
360 self.str.push_str("::");
362 self.str.push_str(text
);