]>
Commit | Line | Data |
---|---|---|
b039eaaf SL |
1 | // Copyright 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. | |
4 | // | |
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. | |
10 | ||
92a42be0 | 11 | use middle::cstore::LOCAL_CRATE; |
b039eaaf SL |
12 | use middle::def_id::{DefId, DefIndex}; |
13 | use rustc_data_structures::fnv::FnvHashMap; | |
14 | use rustc_front::hir; | |
15 | use syntax::ast; | |
16 | use syntax::parse::token::InternedString; | |
17 | use util::nodemap::NodeMap; | |
18 | ||
19 | #[derive(Clone)] | |
20 | pub struct Definitions { | |
21 | data: Vec<DefData>, | |
22 | key_map: FnvHashMap<DefKey, DefIndex>, | |
23 | node_map: NodeMap<DefIndex>, | |
24 | } | |
25 | ||
26 | /// A unique identifier that we can use to lookup a definition | |
27 | /// precisely. It combines the index of the definition's parent (if | |
28 | /// any) with a `DisambiguatedDefPathData`. | |
29 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] | |
30 | pub struct DefKey { | |
31 | /// Parent path. | |
32 | pub parent: Option<DefIndex>, | |
33 | ||
34 | /// Identifier of this node. | |
35 | pub disambiguated_data: DisambiguatedDefPathData, | |
36 | } | |
37 | ||
38 | /// Pair of `DefPathData` and an integer disambiguator. The integer is | |
39 | /// normally 0, but in the event that there are multiple defs with the | |
40 | /// same `parent` and `data`, we use this field to disambiguate | |
41 | /// between them. This introduces some artificial ordering dependency | |
42 | /// but means that if you have (e.g.) two impls for the same type in | |
43 | /// the same module, they do get distinct def-ids. | |
44 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] | |
45 | pub struct DisambiguatedDefPathData { | |
46 | pub data: DefPathData, | |
47 | pub disambiguator: u32 | |
48 | } | |
49 | ||
50 | /// For each definition, we track the following data. A definition | |
51 | /// here is defined somewhat circularly as "something with a def-id", | |
52 | /// but it generally corresponds to things like structs, enums, etc. | |
53 | /// There are also some rather random cases (like const initializer | |
54 | /// expressions) that are mostly just leftovers. | |
55 | #[derive(Clone, Debug)] | |
56 | pub struct DefData { | |
57 | pub key: DefKey, | |
58 | ||
59 | /// Local ID within the HIR. | |
60 | pub node_id: ast::NodeId, | |
61 | } | |
62 | ||
63 | pub type DefPath = Vec<DisambiguatedDefPathData>; | |
64 | ||
65 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] | |
66 | pub enum DefPathData { | |
67 | // Root: these should only be used for the root nodes, because | |
68 | // they are treated specially by the `def_path` function. | |
69 | CrateRoot, | |
70 | InlinedRoot(DefPath), | |
71 | ||
72 | // Catch-all for random DefId things like DUMMY_NODE_ID | |
73 | Misc, | |
74 | ||
75 | // Different kinds of items and item-like things: | |
9cc50fc6 | 76 | Impl(ast::Name), |
b039eaaf SL |
77 | Type(ast::Name), |
78 | Mod(ast::Name), | |
79 | Value(ast::Name), | |
80 | MacroDef(ast::Name), | |
81 | ClosureExpr, | |
82 | ||
83 | // Subportions of items | |
84 | TypeParam(ast::Name), | |
85 | LifetimeDef(ast::Name), | |
86 | EnumVariant(ast::Name), | |
87 | PositionalField, | |
88 | Field(hir::StructFieldKind), | |
89 | StructCtor, // implicit ctor for a tuple-like struct | |
90 | Initializer, // initializer for a const | |
91 | Binding(ast::Name), // pattern binding | |
92 | ||
93 | // An external crate that does not have an `extern crate` in this | |
94 | // crate. | |
95 | DetachedCrate(ast::Name), | |
96 | } | |
97 | ||
98 | impl Definitions { | |
99 | pub fn new() -> Definitions { | |
100 | Definitions { | |
101 | data: vec![], | |
102 | key_map: FnvHashMap(), | |
103 | node_map: NodeMap(), | |
104 | } | |
105 | } | |
106 | ||
107 | pub fn len(&self) -> usize { | |
108 | self.data.len() | |
109 | } | |
110 | ||
111 | pub fn def_key(&self, index: DefIndex) -> DefKey { | |
112 | self.data[index.as_usize()].key.clone() | |
113 | } | |
114 | ||
115 | /// Returns the path from the crate root to `index`. The root | |
116 | /// nodes are not included in the path (i.e., this will be an | |
117 | /// empty vector for the crate root). For an inlined item, this | |
118 | /// will be the path of the item in the external crate (but the | |
119 | /// path will begin with the path to the external crate). | |
120 | pub fn def_path(&self, index: DefIndex) -> DefPath { | |
121 | make_def_path(index, |p| self.def_key(p)) | |
122 | } | |
123 | ||
124 | pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> { | |
125 | self.node_map.get(&node).cloned() | |
126 | } | |
127 | ||
128 | pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> { | |
129 | self.opt_def_index(node).map(DefId::local) | |
130 | } | |
131 | ||
132 | pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> { | |
133 | if def_id.krate == LOCAL_CRATE { | |
134 | assert!(def_id.index.as_usize() < self.data.len()); | |
135 | Some(self.data[def_id.index.as_usize()].node_id) | |
136 | } else { | |
137 | None | |
138 | } | |
139 | } | |
140 | ||
141 | pub fn create_def_with_parent(&mut self, | |
142 | parent: Option<DefIndex>, | |
143 | node_id: ast::NodeId, | |
144 | data: DefPathData) | |
145 | -> DefIndex { | |
146 | assert!(!self.node_map.contains_key(&node_id), | |
147 | "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", | |
148 | node_id, | |
149 | data, | |
150 | self.data[self.node_map[&node_id].as_usize()]); | |
151 | ||
152 | // Find a unique DefKey. This basically means incrementing the disambiguator | |
153 | // until we get no match. | |
154 | let mut key = DefKey { | |
155 | parent: parent, | |
156 | disambiguated_data: DisambiguatedDefPathData { | |
157 | data: data, | |
158 | disambiguator: 0 | |
159 | } | |
160 | }; | |
161 | ||
162 | while self.key_map.contains_key(&key) { | |
163 | key.disambiguated_data.disambiguator += 1; | |
164 | } | |
165 | ||
166 | // Create the definition. | |
167 | let index = DefIndex::new(self.data.len()); | |
168 | self.data.push(DefData { key: key.clone(), node_id: node_id }); | |
169 | self.node_map.insert(node_id, index); | |
170 | self.key_map.insert(key, index); | |
171 | ||
172 | index | |
173 | } | |
174 | } | |
175 | ||
176 | impl DefPathData { | |
177 | pub fn as_interned_str(&self) -> InternedString { | |
178 | use self::DefPathData::*; | |
179 | match *self { | |
9cc50fc6 | 180 | Impl(name) | |
b039eaaf SL |
181 | Type(name) | |
182 | Mod(name) | | |
183 | Value(name) | | |
184 | MacroDef(name) | | |
185 | TypeParam(name) | | |
186 | LifetimeDef(name) | | |
187 | EnumVariant(name) | | |
188 | DetachedCrate(name) | | |
189 | Binding(name) => { | |
190 | name.as_str() | |
191 | } | |
192 | ||
193 | Field(hir::StructFieldKind::NamedField(name, _)) => { | |
194 | name.as_str() | |
195 | } | |
196 | ||
197 | PositionalField | | |
198 | Field(hir::StructFieldKind::UnnamedField(_)) => { | |
7453a54e | 199 | InternedString::new("{{field}}") |
b039eaaf SL |
200 | } |
201 | ||
202 | // note that this does not show up in user printouts | |
203 | CrateRoot => { | |
7453a54e | 204 | InternedString::new("{{root}}") |
b039eaaf SL |
205 | } |
206 | ||
207 | // note that this does not show up in user printouts | |
208 | InlinedRoot(_) => { | |
7453a54e | 209 | InternedString::new("{{inlined-root}}") |
b039eaaf SL |
210 | } |
211 | ||
212 | Misc => { | |
7453a54e | 213 | InternedString::new("{{?}}") |
b039eaaf SL |
214 | } |
215 | ||
b039eaaf | 216 | ClosureExpr => { |
7453a54e | 217 | InternedString::new("{{closure}}") |
b039eaaf SL |
218 | } |
219 | ||
220 | StructCtor => { | |
7453a54e | 221 | InternedString::new("{{constructor}}") |
b039eaaf SL |
222 | } |
223 | ||
224 | Initializer => { | |
7453a54e | 225 | InternedString::new("{{initializer}}") |
b039eaaf SL |
226 | } |
227 | } | |
228 | } | |
229 | ||
230 | pub fn to_string(&self) -> String { | |
231 | self.as_interned_str().to_string() | |
232 | } | |
233 | } | |
234 | ||
235 | pub fn make_def_path<FN>(start_index: DefIndex, mut get_key: FN) -> DefPath | |
236 | where FN: FnMut(DefIndex) -> DefKey | |
237 | { | |
238 | let mut result = vec![]; | |
239 | let mut index = Some(start_index); | |
240 | while let Some(p) = index { | |
241 | let key = get_key(p); | |
242 | match key.disambiguated_data.data { | |
243 | DefPathData::CrateRoot => { | |
244 | assert!(key.parent.is_none()); | |
245 | break; | |
246 | } | |
247 | DefPathData::InlinedRoot(ref p) => { | |
248 | assert!(key.parent.is_none()); | |
249 | result.extend(p.iter().cloned().rev()); | |
250 | break; | |
251 | } | |
252 | _ => { | |
253 | result.push(key.disambiguated_data); | |
254 | index = key.parent; | |
255 | } | |
256 | } | |
257 | } | |
258 | result.reverse(); | |
259 | result | |
260 | } |