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};
14 use middle::cstore::{ExternCrate, ExternCrateSource};
16 use syntax::symbol::Symbol;
17 use syntax::symbol::LocalInternedString;
22 static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
23 static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
26 /// Enforces that item_path_str always returns an absolute path and
27 /// also enables "type-based" impl paths. This is used when building
28 /// symbols that contain types, where we want the crate name to be
29 /// part of the symbol.
30 pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
31 FORCE_ABSOLUTE.with(|force| {
32 let old = force.get();
40 /// Force us to name impls with just the filename/line number. We
41 /// normally try to use types. But at some points, notably while printing
42 /// cycle errors, this can result in extra or suboptimal error output,
43 /// so this variable disables that check.
44 pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
45 FORCE_IMPL_FILENAME_LINE.with(|force| {
46 let old = force.get();
54 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
55 /// Returns a string identifying this def-id. This string is
56 /// suitable for user output. It is relative to the current crate
57 /// root, unless with_forced_absolute_paths was used.
58 pub fn item_path_str(self, def_id: DefId) -> String {
59 let mode = FORCE_ABSOLUTE.with(|force| {
66 let mut buffer = LocalPathBuffer::new(mode);
67 self.push_item_path(&mut buffer, def_id);
71 /// Returns a string identifying this local node-id.
72 pub fn node_path_str(self, id: ast::NodeId) -> String {
73 self.item_path_str(self.hir.local_def_id(id))
76 /// Returns a string identifying this def-id. This string is
77 /// suitable for user output. It always begins with a crate identifier.
78 pub fn absolute_item_path_str(self, def_id: DefId) -> String {
79 let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
80 self.push_item_path(&mut buffer, def_id);
84 /// Returns the "path" to a particular crate. This can proceed in
85 /// various ways, depending on the `root_mode` of the `buffer`.
86 /// (See `RootMode` enum for more details.)
87 pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum)
88 where T: ItemPathBuffer
90 match *buffer.root_mode() {
92 // In local mode, when we encounter a crate other than
93 // LOCAL_CRATE, execution proceeds in one of two ways:
95 // 1. for a direct dependency, where user added an
96 // `extern crate` manually, we put the `extern
97 // crate` as the parent. So you wind up with
98 // something relative to the current crate.
99 // 2. for an extern inferred from a path or an indirect crate,
100 // where there is no explicit `extern crate`, we just prepend
103 // Returns `None` for the local crate.
104 if cnum != LOCAL_CRATE {
105 let opt_extern_crate = self.extern_crate(cnum.as_def_id());
106 if let Some(ExternCrate {
107 src: ExternCrateSource::Extern(def_id),
110 }) = *opt_extern_crate
112 self.push_item_path(buffer, def_id);
114 buffer.push(&self.crate_name(cnum).as_str());
118 RootMode::Absolute => {
119 // In absolute mode, just write the crate name
121 buffer.push(&self.original_crate_name(cnum).as_str());
126 /// If possible, this pushes a global path resolving to `external_def_id` that is visible
127 /// from at least one local module and returns true. If the crate defining `external_def_id` is
128 /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
129 pub fn try_push_visible_item_path<T>(self, buffer: &mut T, external_def_id: DefId) -> bool
130 where T: ItemPathBuffer
132 let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
134 let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
136 // If `cur_def` is a direct or injected extern crate, push the path to the crate
137 // followed by the path to the item within the crate and return.
138 if cur_def.index == CRATE_DEF_INDEX {
139 match *self.extern_crate(cur_def) {
141 src: ExternCrateSource::Extern(def_id),
145 self.push_item_path(buffer, def_id);
146 cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
150 buffer.push(&self.crate_name(cur_def.krate).as_str());
151 cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
158 let mut cur_def_key = self.def_key(cur_def);
160 // For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
161 if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
163 krate: cur_def.krate,
164 index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
167 cur_def_key = self.def_key(parent);
170 let data = cur_def_key.disambiguated_data.data;
171 let symbol = data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
172 Symbol::intern("<unnamed>").as_str()
174 cur_path.push(symbol);
176 match visible_parent_map.get(&cur_def) {
177 Some(&def) => cur_def = def,
178 None => return false,
183 pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
184 where T: ItemPathBuffer
186 match *buffer.root_mode() {
187 RootMode::Local if !def_id.is_local() =>
188 if self.try_push_visible_item_path(buffer, def_id) { return },
192 let key = self.def_key(def_id);
193 match key.disambiguated_data.data {
194 DefPathData::CrateRoot => {
195 assert!(key.parent.is_none());
196 self.push_krate_path(buffer, def_id.krate);
199 DefPathData::Impl => {
200 self.push_impl_path(buffer, def_id);
203 // Unclear if there is any value in distinguishing these.
204 // Probably eventually (and maybe we would even want
205 // finer-grained distinctions, e.g. between enum/struct).
206 data @ DefPathData::Misc |
207 data @ DefPathData::TypeNs(..) |
208 data @ DefPathData::Trait(..) |
209 data @ DefPathData::AssocTypeInTrait(..) |
210 data @ DefPathData::AssocTypeInImpl(..) |
211 data @ DefPathData::ValueNs(..) |
212 data @ DefPathData::Module(..) |
213 data @ DefPathData::TypeParam(..) |
214 data @ DefPathData::LifetimeDef(..) |
215 data @ DefPathData::EnumVariant(..) |
216 data @ DefPathData::Field(..) |
217 data @ DefPathData::Initializer |
218 data @ DefPathData::MacroDef(..) |
219 data @ DefPathData::ClosureExpr |
220 data @ DefPathData::ImplTrait |
221 data @ DefPathData::Typeof |
222 data @ DefPathData::GlobalMetaData(..) => {
223 let parent_def_id = self.parent_def_id(def_id).unwrap();
224 self.push_item_path(buffer, parent_def_id);
225 buffer.push(&data.as_interned_str().as_symbol().as_str());
227 DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
228 let parent_def_id = self.parent_def_id(def_id).unwrap();
229 self.push_item_path(buffer, parent_def_id);
234 fn push_impl_path<T>(self,
237 where T: ItemPathBuffer
239 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
241 // Always use types for non-local impls, where types are always
242 // available, and filename/line-number is mostly uninteresting.
243 let use_types = !impl_def_id.is_local() || {
244 // Otherwise, use filename/line-number if forced.
245 let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
250 return self.push_impl_path_fallback(buffer, impl_def_id);
253 // Decide whether to print the parent path for the impl.
254 // Logically, since impls are global, it's never needed, but
255 // users may find it useful. Currently, we omit the parent if
256 // the impl is either in the same module as the self-type or
258 let self_ty = self.type_of(impl_def_id);
259 let in_self_mod = match characteristic_def_id_of_type(self_ty) {
261 Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
264 let impl_trait_ref = self.impl_trait_ref(impl_def_id);
265 let in_trait_mod = match impl_trait_ref {
267 Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
270 if !in_self_mod && !in_trait_mod {
271 // If the impl is not co-located with either self-type or
272 // trait-type, then fallback to a format that identifies
273 // the module more clearly.
274 self.push_item_path(buffer, parent_def_id);
275 if let Some(trait_ref) = impl_trait_ref {
276 buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
278 buffer.push(&format!("<impl {}>", self_ty));
283 // Otherwise, try to give a good form that would be valid language
284 // syntax. Preferably using associated item notation.
286 if let Some(trait_ref) = impl_trait_ref {
288 buffer.push(&format!("<{} as {}>",
294 // Inherent impls. Try to print `Foo::bar` for an inherent
295 // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
296 // anything other than a simple path.
298 ty::TyAdt(adt_def, substs) => {
299 if substs.types().next().is_none() { // ignore regions
300 self.push_item_path(buffer, adt_def.did);
302 buffer.push(&format!("<{}>", self_ty));
306 ty::TyForeign(did) => self.push_item_path(buffer, did),
314 buffer.push(&format!("{}", self_ty));
318 buffer.push(&format!("<{}>", self_ty));
323 fn push_impl_path_fallback<T>(self,
326 where T: ItemPathBuffer
328 // If no type info is available, fall back to
329 // pretty printing some span information. This should
330 // only occur very early in the compiler pipeline.
331 let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
332 self.push_item_path(buffer, parent_def_id);
333 let node_id = self.hir.as_local_node_id(impl_def_id).unwrap();
334 let item = self.hir.expect_item(node_id);
335 let span_str = self.sess.codemap().span_to_string(item.span);
336 buffer.push(&format!("<impl at {}>", span_str));
339 /// Returns the def-id of `def_id`'s parent in the def tree. If
340 /// this returns `None`, then `def_id` represents a crate root or
342 pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
343 let key = self.def_key(def_id);
344 key.parent.map(|index| DefId { krate: def_id.krate, index: index })
348 /// As a heuristic, when we see an impl, if we see that the
349 /// 'self-type' is a type defined in the same module as the impl,
350 /// we can omit including the path to the impl itself. This
351 /// function tries to find a "characteristic def-id" for a
352 /// type. It's just a heuristic so it makes some questionable
353 /// decisions and we may want to adjust it later.
354 pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
356 ty::TyAdt(adt_def, _) => Some(adt_def.did),
358 ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
360 ty::TyArray(subty, _) |
361 ty::TySlice(subty) => characteristic_def_id_of_type(subty),
364 ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty),
366 ty::TyTuple(ref tys) => tys.iter()
367 .filter_map(|ty| characteristic_def_id_of_type(ty))
370 ty::TyFnDef(def_id, _) |
371 ty::TyClosure(def_id, _) |
372 ty::TyGenerator(def_id, _, _) |
373 ty::TyForeign(def_id) => Some(def_id),
381 ty::TyProjection(_) |
386 ty::TyGeneratorWitness(..) |
388 ty::TyFloat(_) => None,
392 /// Unifying Trait for different kinds of item paths we might
393 /// construct. The basic interface is that components get pushed: the
394 /// instance can also customize how we handle the root of a crate.
395 pub trait ItemPathBuffer {
396 fn root_mode(&self) -> &RootMode;
397 fn push(&mut self, text: &str);
402 /// Try to make a path relative to the local crate. In
403 /// particular, local paths have no prefix, and if the path comes
404 /// from an extern crate, start with the path to the `extern
405 /// crate` declaration.
408 /// Always prepend the crate name to the path, forming an absolute
409 /// path from within a given set of crates.
414 struct LocalPathBuffer {
419 impl LocalPathBuffer {
420 fn new(root_mode: RootMode) -> LocalPathBuffer {
427 fn into_string(self) -> String {
432 impl ItemPathBuffer for LocalPathBuffer {
433 fn root_mode(&self) -> &RootMode {
437 fn push(&mut self, text: &str) {
438 if !self.str.is_empty() {
439 self.str.push_str("::");
441 self.str.push_str(text);