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 hir
::def_id
::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
13 use ty
::{self, Ty, TyCtxt}
;
15 use syntax
::symbol
::Symbol
;
20 static FORCE_ABSOLUTE
: Cell
<bool
> = Cell
::new(false)
23 /// Enforces that item_path_str always returns an absolute path.
24 /// This is useful when building symbols that contain types,
25 /// where we want the crate name to be part of the symbol.
26 pub fn with_forced_absolute_paths
<F
: FnOnce() -> R
, R
>(f
: F
) -> R
{
27 FORCE_ABSOLUTE
.with(|force
| {
28 let old
= force
.get();
36 impl<'a
, 'gcx
, 'tcx
> TyCtxt
<'a
, 'gcx
, 'tcx
> {
37 /// Returns a string identifying this def-id. This string is
38 /// suitable for user output. It is relative to the current crate
39 /// root, unless with_forced_absolute_paths was used.
40 pub fn item_path_str(self, def_id
: DefId
) -> String
{
41 let mode
= FORCE_ABSOLUTE
.with(|force
| {
48 let mut buffer
= LocalPathBuffer
::new(mode
);
49 self.push_item_path(&mut buffer
, def_id
);
53 /// Returns a string identifying this local node-id.
54 pub fn node_path_str(self, id
: ast
::NodeId
) -> String
{
55 self.item_path_str(self.hir
.local_def_id(id
))
58 /// Returns a string identifying this def-id. This string is
59 /// suitable for user output. It always begins with a crate identifier.
60 pub fn absolute_item_path_str(self, def_id
: DefId
) -> String
{
61 let mut buffer
= LocalPathBuffer
::new(RootMode
::Absolute
);
62 self.push_item_path(&mut buffer
, def_id
);
66 /// Returns the "path" to a particular crate. This can proceed in
67 /// various ways, depending on the `root_mode` of the `buffer`.
68 /// (See `RootMode` enum for more details.)
69 pub fn push_krate_path
<T
>(self, buffer
: &mut T
, cnum
: CrateNum
)
70 where T
: ItemPathBuffer
72 match *buffer
.root_mode() {
74 // In local mode, when we encounter a crate other than
75 // LOCAL_CRATE, execution proceeds in one of two ways:
77 // 1. for a direct dependency, where user added an
78 // `extern crate` manually, we put the `extern
79 // crate` as the parent. So you wind up with
80 // something relative to the current crate.
81 // 2. for an indirect crate, where there is no extern
82 // crate, we just prepend the crate name.
84 // Returns `None` for the local crate.
85 if cnum
!= LOCAL_CRATE
{
86 let opt_extern_crate
= self.sess
.cstore
.extern_crate(cnum
);
87 let opt_extern_crate
= opt_extern_crate
.and_then(|extern_crate
| {
88 if extern_crate
.direct
{
89 Some(extern_crate
.def_id
)
94 if let Some(extern_crate_def_id
) = opt_extern_crate
{
95 self.push_item_path(buffer
, extern_crate_def_id
);
97 buffer
.push(&self.crate_name(cnum
).as_str());
101 RootMode
::Absolute
=> {
102 // In absolute mode, just write the crate name
104 buffer
.push(&self.original_crate_name(cnum
).as_str());
109 /// If possible, this pushes a global path resolving to `external_def_id` that is visible
110 /// from at least one local module and returns true. If the crate defining `external_def_id` is
111 /// declared with an `extern crate`, the path is guarenteed to use the `extern crate`.
112 pub fn try_push_visible_item_path
<T
>(self, buffer
: &mut T
, external_def_id
: DefId
) -> bool
113 where T
: ItemPathBuffer
115 let visible_parent_map
= self.sess
.cstore
.visible_parent_map();
117 let (mut cur_def
, mut cur_path
) = (external_def_id
, Vec
::<ast
::Name
>::new());
119 // If `cur_def` is a direct or injected extern crate, push the path to the crate
120 // followed by the path to the item within the crate and return.
121 if cur_def
.index
== CRATE_DEF_INDEX
{
122 match self.sess
.cstore
.extern_crate(cur_def
.krate
) {
123 Some(extern_crate
) if extern_crate
.direct
=> {
124 self.push_item_path(buffer
, extern_crate
.def_id
);
125 cur_path
.iter().rev().map(|segment
| buffer
.push(&segment
.as_str())).count();
129 buffer
.push(&self.crate_name(cur_def
.krate
).as_str());
130 cur_path
.iter().rev().map(|segment
| buffer
.push(&segment
.as_str())).count();
137 cur_path
.push(self.sess
.cstore
.def_key(cur_def
)
138 .disambiguated_data
.data
.get_opt_name().unwrap_or_else(||
139 Symbol
::intern("<unnamed>")));
140 match visible_parent_map
.get(&cur_def
) {
141 Some(&def
) => cur_def
= def
,
142 None
=> return false,
147 pub fn push_item_path
<T
>(self, buffer
: &mut T
, def_id
: DefId
)
148 where T
: ItemPathBuffer
150 match *buffer
.root_mode() {
151 RootMode
::Local
if !def_id
.is_local() =>
152 if self.try_push_visible_item_path(buffer
, def_id
) { return }
,
156 let key
= self.def_key(def_id
);
157 match key
.disambiguated_data
.data
{
158 DefPathData
::CrateRoot
=> {
159 assert
!(key
.parent
.is_none());
160 self.push_krate_path(buffer
, def_id
.krate
);
163 DefPathData
::Impl
=> {
164 self.push_impl_path(buffer
, def_id
);
167 // Unclear if there is any value in distinguishing these.
168 // Probably eventually (and maybe we would even want
169 // finer-grained distinctions, e.g. between enum/struct).
170 data @ DefPathData
::Misc
|
171 data @ DefPathData
::TypeNs(..) |
172 data @ DefPathData
::ValueNs(..) |
173 data @ DefPathData
::Module(..) |
174 data @ DefPathData
::TypeParam(..) |
175 data @ DefPathData
::LifetimeDef(..) |
176 data @ DefPathData
::EnumVariant(..) |
177 data @ DefPathData
::Field(..) |
178 data @ DefPathData
::StructCtor
|
179 data @ DefPathData
::Initializer
|
180 data @ DefPathData
::MacroDef(..) |
181 data @ DefPathData
::ClosureExpr
|
182 data @ DefPathData
::Binding(..) |
183 data @ DefPathData
::ImplTrait
|
184 data @ DefPathData
::Typeof
=> {
185 let parent_def_id
= self.parent_def_id(def_id
).unwrap();
186 self.push_item_path(buffer
, parent_def_id
);
187 buffer
.push(&data
.as_interned_str());
192 fn push_impl_path
<T
>(self,
195 where T
: ItemPathBuffer
197 let parent_def_id
= self.parent_def_id(impl_def_id
).unwrap();
199 let use_types
= if !impl_def_id
.is_local() {
200 // always have full types available for extern crates
203 // for local crates, check whether type info is
204 // available; typeck might not have completed yet
205 self.maps
.impl_trait_ref
.borrow().contains_key(&impl_def_id
)
209 return self.push_impl_path_fallback(buffer
, impl_def_id
);
212 // Decide whether to print the parent path for the impl.
213 // Logically, since impls are global, it's never needed, but
214 // users may find it useful. Currently, we omit the parent if
215 // the impl is either in the same module as the self-type or
217 let self_ty
= self.item_type(impl_def_id
);
218 let in_self_mod
= match characteristic_def_id_of_type(self_ty
) {
220 Some(ty_def_id
) => self.parent_def_id(ty_def_id
) == Some(parent_def_id
),
223 let impl_trait_ref
= self.impl_trait_ref(impl_def_id
);
224 let in_trait_mod
= match impl_trait_ref
{
226 Some(trait_ref
) => self.parent_def_id(trait_ref
.def_id
) == Some(parent_def_id
),
229 if !in_self_mod
&& !in_trait_mod
{
230 // If the impl is not co-located with either self-type or
231 // trait-type, then fallback to a format that identifies
232 // the module more clearly.
233 self.push_item_path(buffer
, parent_def_id
);
234 if let Some(trait_ref
) = impl_trait_ref
{
235 buffer
.push(&format
!("<impl {} for {}>", trait_ref
, self_ty
));
237 buffer
.push(&format
!("<impl {}>", self_ty
));
242 // Otherwise, try to give a good form that would be valid language
243 // syntax. Preferably using associated item notation.
245 if let Some(trait_ref
) = impl_trait_ref
{
247 buffer
.push(&format
!("<{} as {}>",
253 // Inherent impls. Try to print `Foo::bar` for an inherent
254 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
255 // anything other than a simple path.
257 ty
::TyAdt(adt_def
, substs
) => {
258 if substs
.types().next().is_none() { // ignore regions
259 self.push_item_path(buffer
, adt_def
.did
);
261 buffer
.push(&format
!("<{}>", self_ty
));
271 buffer
.push(&format
!("{}", self_ty
));
275 buffer
.push(&format
!("<{}>", self_ty
));
280 fn push_impl_path_fallback
<T
>(self,
283 where T
: ItemPathBuffer
285 // If no type info is available, fall back to
286 // pretty printing some span information. This should
287 // only occur very early in the compiler pipeline.
288 let parent_def_id
= self.parent_def_id(impl_def_id
).unwrap();
289 self.push_item_path(buffer
, parent_def_id
);
290 let node_id
= self.hir
.as_local_node_id(impl_def_id
).unwrap();
291 let item
= self.hir
.expect_item(node_id
);
292 let span_str
= self.sess
.codemap().span_to_string(item
.span
);
293 buffer
.push(&format
!("<impl at {}>", span_str
));
296 /// Returns the def-id of `def_id`'s parent in the def tree. If
297 /// this returns `None`, then `def_id` represents a crate root or
299 pub fn parent_def_id(self, def_id
: DefId
) -> Option
<DefId
> {
300 let key
= self.def_key(def_id
);
301 key
.parent
.map(|index
| DefId { krate: def_id.krate, index: index }
)
305 /// As a heuristic, when we see an impl, if we see that the
306 /// 'self-type' is a type defined in the same module as the impl,
307 /// we can omit including the path to the impl itself. This
308 /// function tries to find a "characteristic def-id" for a
309 /// type. It's just a heuristic so it makes some questionable
310 /// decisions and we may want to adjust it later.
311 pub fn characteristic_def_id_of_type(ty
: Ty
) -> Option
<DefId
> {
313 ty
::TyAdt(adt_def
, _
) => Some(adt_def
.did
),
315 ty
::TyDynamic(data
, ..) => data
.principal().map(|p
| p
.def_id()),
317 ty
::TyArray(subty
, _
) |
318 ty
::TySlice(subty
) => characteristic_def_id_of_type(subty
),
321 ty
::TyRef(_
, mt
) => characteristic_def_id_of_type(mt
.ty
),
323 ty
::TyTuple(ref tys
, _
) => tys
.iter()
324 .filter_map(|ty
| characteristic_def_id_of_type(ty
))
327 ty
::TyFnDef(def_id
, ..) |
328 ty
::TyClosure(def_id
, _
) => Some(def_id
),
336 ty
::TyProjection(_
) |
342 ty
::TyFloat(_
) => None
,
346 /// Unifying Trait for different kinds of item paths we might
347 /// construct. The basic interface is that components get pushed: the
348 /// instance can also customize how we handle the root of a crate.
349 pub trait ItemPathBuffer
{
350 fn root_mode(&self) -> &RootMode
;
351 fn push(&mut self, text
: &str);
356 /// Try to make a path relative to the local crate. In
357 /// particular, local paths have no prefix, and if the path comes
358 /// from an extern crate, start with the path to the `extern
359 /// crate` declaration.
362 /// Always prepend the crate name to the path, forming an absolute
363 /// path from within a given set of crates.
368 struct LocalPathBuffer
{
373 impl LocalPathBuffer
{
374 fn new(root_mode
: RootMode
) -> LocalPathBuffer
{
376 root_mode
: root_mode
,
381 fn into_string(self) -> String
{
387 impl ItemPathBuffer
for LocalPathBuffer
{
388 fn root_mode(&self) -> &RootMode
{
392 fn push(&mut self, text
: &str) {
393 if !self.str.is_empty() {
394 self.str.push_str("::");
396 self.str.push_str(text
);