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}
;
16 use syntax
::parse
::token
;
21 static FORCE_ABSOLUTE
: Cell
<bool
> = Cell
::new(false)
24 /// Enforces that item_path_str always returns an absolute path.
25 /// This is useful when building symbols that contain types,
26 /// where we want the crate name to be part of the symbol.
27 pub fn with_forced_absolute_paths
<F
: FnOnce() -> R
, R
>(f
: F
) -> R
{
28 FORCE_ABSOLUTE
.with(|force
| {
29 let old
= force
.get();
37 impl<'a
, 'gcx
, 'tcx
> TyCtxt
<'a
, 'gcx
, 'tcx
> {
38 /// Returns a string identifying this def-id. This string is
39 /// suitable for user output. It is relative to the current crate
40 /// root, unless with_forced_absolute_paths was used.
41 pub fn item_path_str(self, def_id
: DefId
) -> String
{
42 let mode
= FORCE_ABSOLUTE
.with(|force
| {
49 let mut buffer
= LocalPathBuffer
::new(mode
);
50 self.push_item_path(&mut buffer
, def_id
);
54 /// Returns a string identifying this local node-id.
55 pub fn node_path_str(self, id
: ast
::NodeId
) -> String
{
56 self.item_path_str(self.map
.local_def_id(id
))
59 /// Returns a string identifying this def-id. This string is
60 /// suitable for user output. It always begins with a crate identifier.
61 pub fn absolute_item_path_str(self, def_id
: DefId
) -> String
{
62 let mut buffer
= LocalPathBuffer
::new(RootMode
::Absolute
);
63 self.push_item_path(&mut buffer
, def_id
);
67 /// Returns the "path" to a particular crate. This can proceed in
68 /// various ways, depending on the `root_mode` of the `buffer`.
69 /// (See `RootMode` enum for more details.)
70 pub fn push_krate_path
<T
>(self, buffer
: &mut T
, cnum
: ast
::CrateNum
)
71 where T
: ItemPathBuffer
73 match *buffer
.root_mode() {
75 // In local mode, when we encounter a crate other than
76 // LOCAL_CRATE, execution proceeds in one of two ways:
78 // 1. for a direct dependency, where user added an
79 // `extern crate` manually, we put the `extern
80 // crate` as the parent. So you wind up with
81 // something relative to the current crate.
82 // 2. for an indirect crate, where there is no extern
83 // crate, we just prepend the crate name.
85 // Returns `None` for the local crate.
86 if cnum
!= LOCAL_CRATE
{
87 let opt_extern_crate
= self.sess
.cstore
.extern_crate(cnum
);
88 let opt_extern_crate
= opt_extern_crate
.and_then(|extern_crate
| {
89 if extern_crate
.direct
{
90 Some(extern_crate
.def_id
)
95 if let Some(extern_crate_def_id
) = opt_extern_crate
{
96 self.push_item_path(buffer
, extern_crate_def_id
);
98 buffer
.push(&self.crate_name(cnum
));
102 RootMode
::Absolute
=> {
103 // In absolute mode, just write the crate name
105 if cnum
== LOCAL_CRATE
{
106 buffer
.push(&self.crate_name(cnum
));
108 buffer
.push(&self.sess
.cstore
.original_crate_name(cnum
));
114 /// If possible, this pushes a global path resolving to `external_def_id` that is visible
115 /// from at least one local module and returns true. If the crate defining `external_def_id` is
116 /// declared with an `extern crate`, the path is guarenteed to use the `extern crate`.
117 pub fn try_push_visible_item_path
<T
>(self, buffer
: &mut T
, external_def_id
: DefId
) -> bool
118 where T
: ItemPathBuffer
120 let visible_parent_map
= self.sess
.cstore
.visible_parent_map();
122 let (mut cur_def
, mut cur_path
) = (external_def_id
, Vec
::<ast
::Name
>::new());
124 // If `cur_def` is a direct or injected extern crate, push the path to the crate
125 // followed by the path to the item within the crate and return.
126 if cur_def
.index
== CRATE_DEF_INDEX
{
127 match self.sess
.cstore
.extern_crate(cur_def
.krate
) {
128 Some(extern_crate
) if extern_crate
.direct
=> {
129 self.push_item_path(buffer
, extern_crate
.def_id
);
130 cur_path
.iter().rev().map(|segment
| buffer
.push(&segment
.as_str())).count();
134 buffer
.push(&self.crate_name(cur_def
.krate
));
135 cur_path
.iter().rev().map(|segment
| buffer
.push(&segment
.as_str())).count();
142 cur_path
.push(self.sess
.cstore
.opt_item_name(cur_def
).unwrap_or_else(||
143 token
::intern("<unnamed>")));
144 match visible_parent_map
.get(&cur_def
) {
145 Some(&def
) => cur_def
= def
,
146 None
=> return false,
151 pub fn push_item_path
<T
>(self, buffer
: &mut T
, def_id
: DefId
)
152 where T
: ItemPathBuffer
154 match *buffer
.root_mode() {
155 RootMode
::Local
if !def_id
.is_local() =>
156 if self.try_push_visible_item_path(buffer
, def_id
) { return }
,
160 let key
= self.def_key(def_id
);
161 match key
.disambiguated_data
.data
{
162 DefPathData
::CrateRoot
=> {
163 assert
!(key
.parent
.is_none());
164 self.push_krate_path(buffer
, def_id
.krate
);
167 DefPathData
::InlinedRoot(ref root_path
) => {
168 assert
!(key
.parent
.is_none());
169 self.push_item_path(buffer
, root_path
.def_id
);
172 DefPathData
::Impl
=> {
173 self.push_impl_path(buffer
, def_id
);
176 // Unclear if there is any value in distinguishing these.
177 // Probably eventually (and maybe we would even want
178 // finer-grained distinctions, e.g. between enum/struct).
179 data @ DefPathData
::Misc
|
180 data @ DefPathData
::TypeNs(..) |
181 data @ DefPathData
::ValueNs(..) |
182 data @ DefPathData
::Module(..) |
183 data @ DefPathData
::TypeParam(..) |
184 data @ DefPathData
::LifetimeDef(..) |
185 data @ DefPathData
::EnumVariant(..) |
186 data @ DefPathData
::Field(..) |
187 data @ DefPathData
::StructCtor
|
188 data @ DefPathData
::Initializer
|
189 data @ DefPathData
::MacroDef(..) |
190 data @ DefPathData
::ClosureExpr
|
191 data @ DefPathData
::Binding(..) |
192 data @ DefPathData
::ImplTrait
=> {
193 let parent_def_id
= self.parent_def_id(def_id
).unwrap();
194 self.push_item_path(buffer
, parent_def_id
);
195 buffer
.push(&data
.as_interned_str());
200 fn push_impl_path
<T
>(self,
203 where T
: ItemPathBuffer
205 let parent_def_id
= self.parent_def_id(impl_def_id
).unwrap();
207 let use_types
= if !impl_def_id
.is_local() {
208 // always have full types available for extern crates
211 // for local crates, check whether type info is
212 // available; typeck might not have completed yet
213 self.impl_trait_refs
.borrow().contains_key(&impl_def_id
)
217 return self.push_impl_path_fallback(buffer
, impl_def_id
);
220 // Decide whether to print the parent path for the impl.
221 // Logically, since impls are global, it's never needed, but
222 // users may find it useful. Currently, we omit the parent if
223 // the impl is either in the same module as the self-type or
225 let self_ty
= self.lookup_item_type(impl_def_id
).ty
;
226 let in_self_mod
= match characteristic_def_id_of_type(self_ty
) {
228 Some(ty_def_id
) => self.parent_def_id(ty_def_id
) == Some(parent_def_id
),
231 let impl_trait_ref
= self.impl_trait_ref(impl_def_id
);
232 let in_trait_mod
= match impl_trait_ref
{
234 Some(trait_ref
) => self.parent_def_id(trait_ref
.def_id
) == Some(parent_def_id
),
237 if !in_self_mod
&& !in_trait_mod
{
238 // If the impl is not co-located with either self-type or
239 // trait-type, then fallback to a format that identifies
240 // the module more clearly.
241 self.push_item_path(buffer
, parent_def_id
);
242 if let Some(trait_ref
) = impl_trait_ref
{
243 buffer
.push(&format
!("<impl {} for {}>", trait_ref
, self_ty
));
245 buffer
.push(&format
!("<impl {}>", self_ty
));
250 // Otherwise, try to give a good form that would be valid language
251 // syntax. Preferably using associated item notation.
253 if let Some(trait_ref
) = impl_trait_ref
{
255 buffer
.push(&format
!("<{} as {}>",
261 // Inherent impls. Try to print `Foo::bar` for an inherent
262 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
263 // anything other than a simple path.
265 ty
::TyStruct(adt_def
, substs
) |
266 ty
::TyEnum(adt_def
, substs
) => {
267 if substs
.types
.is_empty() { // ignore regions
268 self.push_item_path(buffer
, adt_def
.did
);
270 buffer
.push(&format
!("<{}>", self_ty
));
280 buffer
.push(&format
!("{}", self_ty
));
284 buffer
.push(&format
!("<{}>", self_ty
));
289 fn push_impl_path_fallback
<T
>(self,
292 where T
: ItemPathBuffer
294 // If no type info is available, fall back to
295 // pretty printing some span information. This should
296 // only occur very early in the compiler pipeline.
297 let parent_def_id
= self.parent_def_id(impl_def_id
).unwrap();
298 self.push_item_path(buffer
, parent_def_id
);
299 let node_id
= self.map
.as_local_node_id(impl_def_id
).unwrap();
300 let item
= self.map
.expect_item(node_id
);
301 let span_str
= self.sess
.codemap().span_to_string(item
.span
);
302 buffer
.push(&format
!("<impl at {}>", span_str
));
305 /// Returns the def-id of `def_id`'s parent in the def tree. If
306 /// this returns `None`, then `def_id` represents a crate root or
308 pub fn parent_def_id(&self, def_id
: DefId
) -> Option
<DefId
> {
309 let key
= self.def_key(def_id
);
310 key
.parent
.map(|index
| DefId { krate: def_id.krate, index: index }
)
314 /// As a heuristic, when we see an impl, if we see that the
315 /// 'self-type' is a type defined in the same module as the impl,
316 /// we can omit including the path to the impl itself. This
317 /// function tries to find a "characteristic def-id" for a
318 /// type. It's just a heuristic so it makes some questionable
319 /// decisions and we may want to adjust it later.
320 pub fn characteristic_def_id_of_type(ty
: Ty
) -> Option
<DefId
> {
322 ty
::TyStruct(adt_def
, _
) |
323 ty
::TyEnum(adt_def
, _
) => Some(adt_def
.did
),
325 ty
::TyTrait(ref data
) => Some(data
.principal_def_id()),
327 ty
::TyArray(subty
, _
) |
329 ty
::TyBox(subty
) => characteristic_def_id_of_type(subty
),
332 ty
::TyRef(_
, mt
) => characteristic_def_id_of_type(mt
.ty
),
334 ty
::TyTuple(ref tys
) => tys
.iter()
335 .filter_map(|ty
| characteristic_def_id_of_type(ty
))
338 ty
::TyFnDef(def_id
, _
, _
) |
339 ty
::TyClosure(def_id
, _
) => Some(def_id
),
347 ty
::TyProjection(_
) |
353 ty
::TyFloat(_
) => None
,
357 /// Unifying Trait for different kinds of item paths we might
358 /// construct. The basic interface is that components get pushed: the
359 /// instance can also customize how we handle the root of a crate.
360 pub trait ItemPathBuffer
{
361 fn root_mode(&self) -> &RootMode
;
362 fn push(&mut self, text
: &str);
367 /// Try to make a path relative to the local crate. In
368 /// particular, local paths have no prefix, and if the path comes
369 /// from an extern crate, start with the path to the `extern
370 /// crate` declaration.
373 /// Always prepend the crate name to the path, forming an absolute
374 /// path from within a given set of crates.
379 struct LocalPathBuffer
{
384 impl LocalPathBuffer
{
385 fn new(root_mode
: RootMode
) -> LocalPathBuffer
{
387 root_mode
: root_mode
,
392 fn into_string(self) -> String
{
398 impl ItemPathBuffer
for LocalPathBuffer
{
399 fn root_mode(&self) -> &RootMode
{
403 fn push(&mut self, text
: &str) {
404 if !self.str.is_empty() {
405 self.str.push_str("::");
407 self.str.push_str(text
);