]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
223e47cc LB |
11 | use ast::*; |
12 | use ast; | |
1a4d82fc JJ |
13 | use codemap; |
14 | use codemap::Span; | |
223e47cc | 15 | use parse::token; |
1a4d82fc JJ |
16 | use print::pprust; |
17 | use ptr::P; | |
e9174d1e | 18 | use visit::{FnKind, Visitor}; |
223e47cc | 19 | use visit; |
223e47cc | 20 | |
1a4d82fc JJ |
21 | use std::cmp; |
22 | use std::u32; | |
223e47cc | 23 | |
1a4d82fc | 24 | pub fn path_name_i(idents: &[Ident]) -> String { |
223e47cc | 25 | // FIXME: Bad copies (#2543 -- same for everything else that says "bad") |
c1a9b12d | 26 | idents.iter().map(|i| i.to_string()).collect::<Vec<String>>().join("::") |
223e47cc LB |
27 | } |
28 | ||
1a4d82fc | 29 | pub fn is_path(e: P<Expr>) -> bool { |
7453a54e | 30 | match e.node { ExprKind::Path(..) => true, _ => false } |
223e47cc LB |
31 | } |
32 | ||
1a4d82fc JJ |
33 | |
34 | // convert a span and an identifier to the corresponding | |
35 | // 1-segment path | |
36 | pub fn ident_to_path(s: Span, identifier: Ident) -> Path { | |
37 | ast::Path { | |
38 | span: s, | |
39 | global: false, | |
40 | segments: vec!( | |
41 | ast::PathSegment { | |
42 | identifier: identifier, | |
9cc50fc6 | 43 | parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { |
1a4d82fc | 44 | lifetimes: Vec::new(), |
9cc50fc6 SL |
45 | types: P::empty(), |
46 | bindings: P::empty(), | |
1a4d82fc JJ |
47 | }) |
48 | } | |
49 | ), | |
223e47cc LB |
50 | } |
51 | } | |
52 | ||
1a4d82fc JJ |
53 | // If path is a single segment ident path, return that ident. Otherwise, return |
54 | // None. | |
55 | pub fn path_to_ident(path: &Path) -> Option<Ident> { | |
56 | if path.segments.len() != 1 { | |
57 | return None; | |
223e47cc | 58 | } |
223e47cc | 59 | |
1a4d82fc JJ |
60 | let segment = &path.segments[0]; |
61 | if !segment.parameters.is_empty() { | |
62 | return None; | |
63 | } | |
223e47cc | 64 | |
1a4d82fc | 65 | Some(segment.identifier) |
223e47cc LB |
66 | } |
67 | ||
1a4d82fc | 68 | pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> P<Pat> { |
7453a54e | 69 | let spanned = codemap::Spanned{ span: s, node: i }; |
1a4d82fc JJ |
70 | P(Pat { |
71 | id: id, | |
7453a54e | 72 | node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), |
1a4d82fc JJ |
73 | span: s |
74 | }) | |
223e47cc LB |
75 | } |
76 | ||
1a4d82fc JJ |
77 | /// Generate a "pretty" name for an `impl` from its type and trait. |
78 | /// This is designed so that symbols of `impl`'d methods give some | |
79 | /// hint of where they came from, (previously they would all just be | |
80 | /// listed as `__extensions__::method_name::hash`, with no indication | |
81 | /// of the type). | |
c34b1796 AL |
82 | pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: Option<&Ty>) -> Ident { |
83 | let mut pretty = match ty { | |
84 | Some(t) => pprust::ty_to_string(t), | |
d9579d0f | 85 | None => String::from("..") |
c34b1796 AL |
86 | }; |
87 | ||
1a4d82fc JJ |
88 | match *trait_ref { |
89 | Some(ref trait_ref) => { | |
90 | pretty.push('.'); | |
85aaf69f | 91 | pretty.push_str(&pprust::path_to_string(&trait_ref.path)); |
223e47cc | 92 | } |
1a4d82fc JJ |
93 | None => {} |
94 | } | |
85aaf69f | 95 | token::gensym_ident(&pretty[..]) |
1a4d82fc JJ |
96 | } |
97 | ||
1a4d82fc | 98 | pub fn struct_field_visibility(field: ast::StructField) -> Visibility { |
223e47cc | 99 | match field.node.kind { |
1a4d82fc | 100 | ast::NamedField(_, v) | ast::UnnamedField(v) => v |
223e47cc LB |
101 | } |
102 | } | |
103 | ||
223e47cc LB |
104 | // ______________________________________________________________________ |
105 | // Enumerating the IDs which appear in an AST | |
106 | ||
c34b1796 | 107 | #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] |
1a4d82fc JJ |
108 | pub struct IdRange { |
109 | pub min: NodeId, | |
110 | pub max: NodeId, | |
223e47cc LB |
111 | } |
112 | ||
1a4d82fc JJ |
113 | impl IdRange { |
114 | pub fn max() -> IdRange { | |
115 | IdRange { | |
116 | min: u32::MAX, | |
117 | max: u32::MIN, | |
970d7e83 LB |
118 | } |
119 | } | |
120 | ||
121 | pub fn empty(&self) -> bool { | |
122 | self.min >= self.max | |
123 | } | |
124 | ||
1a4d82fc JJ |
125 | pub fn add(&mut self, id: NodeId) { |
126 | self.min = cmp::min(self.min, id); | |
127 | self.max = cmp::max(self.max, id + 1); | |
970d7e83 | 128 | } |
223e47cc LB |
129 | } |
130 | ||
1a4d82fc JJ |
131 | pub trait IdVisitingOperation { |
132 | fn visit_id(&mut self, node_id: NodeId); | |
133 | } | |
223e47cc | 134 | |
1a4d82fc JJ |
135 | /// A visitor that applies its operation to all of the node IDs |
136 | /// in a visitable thing. | |
223e47cc | 137 | |
1a4d82fc JJ |
138 | pub struct IdVisitor<'a, O:'a> { |
139 | pub operation: &'a mut O, | |
1a4d82fc JJ |
140 | pub visited_outermost: bool, |
141 | } | |
223e47cc | 142 | |
1a4d82fc JJ |
143 | impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { |
144 | fn visit_generics_helper(&mut self, generics: &Generics) { | |
62682a34 | 145 | for type_parameter in generics.ty_params.iter() { |
1a4d82fc JJ |
146 | self.operation.visit_id(type_parameter.id) |
147 | } | |
85aaf69f | 148 | for lifetime in &generics.lifetimes { |
1a4d82fc JJ |
149 | self.operation.visit_id(lifetime.lifetime.id) |
150 | } | |
151 | } | |
152 | } | |
223e47cc | 153 | |
1a4d82fc JJ |
154 | impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { |
155 | fn visit_mod(&mut self, | |
156 | module: &Mod, | |
157 | _: Span, | |
158 | node_id: NodeId) { | |
159 | self.operation.visit_id(node_id); | |
160 | visit::walk_mod(self, module) | |
161 | } | |
223e47cc | 162 | |
1a4d82fc JJ |
163 | fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { |
164 | self.operation.visit_id(foreign_item.id); | |
165 | visit::walk_foreign_item(self, foreign_item) | |
166 | } | |
223e47cc | 167 | |
1a4d82fc | 168 | fn visit_item(&mut self, item: &Item) { |
92a42be0 SL |
169 | if self.visited_outermost { |
170 | return | |
171 | } else { | |
172 | self.visited_outermost = true | |
1a4d82fc | 173 | } |
223e47cc | 174 | |
1a4d82fc | 175 | self.operation.visit_id(item.id); |
85aaf69f | 176 | match item.node { |
7453a54e | 177 | ItemKind::Use(ref view_path) => { |
85aaf69f SL |
178 | match view_path.node { |
179 | ViewPathSimple(_, _) | | |
180 | ViewPathGlob(_) => {} | |
181 | ViewPathList(_, ref paths) => { | |
182 | for path in paths { | |
183 | self.operation.visit_id(path.node.id()) | |
184 | } | |
185 | } | |
186 | } | |
187 | } | |
85aaf69f | 188 | _ => {} |
1a4d82fc | 189 | } |
970d7e83 | 190 | |
1a4d82fc | 191 | visit::walk_item(self, item); |
223e47cc | 192 | |
1a4d82fc JJ |
193 | self.visited_outermost = false |
194 | } | |
223e47cc | 195 | |
1a4d82fc JJ |
196 | fn visit_local(&mut self, local: &Local) { |
197 | self.operation.visit_id(local.id); | |
198 | visit::walk_local(self, local) | |
199 | } | |
223e47cc | 200 | |
1a4d82fc JJ |
201 | fn visit_block(&mut self, block: &Block) { |
202 | self.operation.visit_id(block.id); | |
203 | visit::walk_block(self, block) | |
223e47cc | 204 | } |
223e47cc | 205 | |
1a4d82fc | 206 | fn visit_stmt(&mut self, statement: &Stmt) { |
b039eaaf | 207 | self.operation |
9cc50fc6 | 208 | .visit_id(statement.node.id().expect("attempted to visit unexpanded stmt")); |
1a4d82fc JJ |
209 | visit::walk_stmt(self, statement) |
210 | } | |
223e47cc | 211 | |
1a4d82fc JJ |
212 | fn visit_pat(&mut self, pattern: &Pat) { |
213 | self.operation.visit_id(pattern.id); | |
214 | visit::walk_pat(self, pattern) | |
223e47cc | 215 | } |
223e47cc | 216 | |
1a4d82fc JJ |
217 | fn visit_expr(&mut self, expression: &Expr) { |
218 | self.operation.visit_id(expression.id); | |
219 | visit::walk_expr(self, expression) | |
970d7e83 LB |
220 | } |
221 | ||
1a4d82fc JJ |
222 | fn visit_ty(&mut self, typ: &Ty) { |
223 | self.operation.visit_id(typ.id); | |
1a4d82fc JJ |
224 | visit::walk_ty(self, typ) |
225 | } | |
226 | ||
227 | fn visit_generics(&mut self, generics: &Generics) { | |
228 | self.visit_generics_helper(generics); | |
229 | visit::walk_generics(self, generics) | |
230 | } | |
231 | ||
232 | fn visit_fn(&mut self, | |
233 | function_kind: visit::FnKind<'v>, | |
234 | function_declaration: &'v FnDecl, | |
235 | block: &'v Block, | |
236 | span: Span, | |
237 | node_id: NodeId) { | |
92a42be0 SL |
238 | match function_kind { |
239 | FnKind::Method(..) if self.visited_outermost => return, | |
240 | FnKind::Method(..) => self.visited_outermost = true, | |
241 | _ => {} | |
223e47cc | 242 | } |
1a4d82fc JJ |
243 | |
244 | self.operation.visit_id(node_id); | |
245 | ||
246 | match function_kind { | |
e9174d1e | 247 | FnKind::ItemFn(_, generics, _, _, _, _) => { |
1a4d82fc JJ |
248 | self.visit_generics_helper(generics) |
249 | } | |
e9174d1e | 250 | FnKind::Method(_, sig, _) => { |
c34b1796 AL |
251 | self.visit_generics_helper(&sig.generics) |
252 | } | |
e9174d1e | 253 | FnKind::Closure => {} |
223e47cc | 254 | } |
1a4d82fc | 255 | |
85aaf69f | 256 | for argument in &function_declaration.inputs { |
1a4d82fc | 257 | self.operation.visit_id(argument.id) |
223e47cc | 258 | } |
1a4d82fc JJ |
259 | |
260 | visit::walk_fn(self, | |
261 | function_kind, | |
262 | function_declaration, | |
263 | block, | |
264 | span); | |
265 | ||
92a42be0 SL |
266 | if let FnKind::Method(..) = function_kind { |
267 | self.visited_outermost = false; | |
970d7e83 | 268 | } |
223e47cc | 269 | } |
223e47cc | 270 | |
1a4d82fc JJ |
271 | fn visit_struct_field(&mut self, struct_field: &StructField) { |
272 | self.operation.visit_id(struct_field.node.id); | |
273 | visit::walk_struct_field(self, struct_field) | |
274 | } | |
970d7e83 | 275 | |
b039eaaf SL |
276 | fn visit_variant_data(&mut self, |
277 | struct_def: &VariantData, | |
1a4d82fc JJ |
278 | _: ast::Ident, |
279 | _: &ast::Generics, | |
b039eaaf SL |
280 | _: NodeId, |
281 | _: Span) { | |
282 | self.operation.visit_id(struct_def.id()); | |
1a4d82fc | 283 | visit::walk_struct_def(self, struct_def); |
970d7e83 | 284 | } |
970d7e83 | 285 | |
c34b1796 AL |
286 | fn visit_trait_item(&mut self, ti: &ast::TraitItem) { |
287 | self.operation.visit_id(ti.id); | |
288 | visit::walk_trait_item(self, ti); | |
223e47cc | 289 | } |
223e47cc | 290 | |
c34b1796 AL |
291 | fn visit_impl_item(&mut self, ii: &ast::ImplItem) { |
292 | self.operation.visit_id(ii.id); | |
293 | visit::walk_impl_item(self, ii); | |
294 | } | |
295 | ||
b039eaaf | 296 | fn visit_lifetime(&mut self, lifetime: &Lifetime) { |
1a4d82fc JJ |
297 | self.operation.visit_id(lifetime.id); |
298 | } | |
223e47cc | 299 | |
c34b1796 | 300 | fn visit_lifetime_def(&mut self, def: &LifetimeDef) { |
b039eaaf | 301 | self.visit_lifetime(&def.lifetime); |
223e47cc | 302 | } |
c34b1796 AL |
303 | |
304 | fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { | |
305 | self.operation.visit_id(trait_ref.ref_id); | |
306 | visit::walk_trait_ref(self, trait_ref); | |
307 | } | |
223e47cc LB |
308 | } |
309 | ||
e9174d1e SL |
310 | pub struct IdRangeComputingVisitor { |
311 | pub result: IdRange, | |
223e47cc LB |
312 | } |
313 | ||
e9174d1e SL |
314 | impl IdRangeComputingVisitor { |
315 | pub fn new() -> IdRangeComputingVisitor { | |
316 | IdRangeComputingVisitor { result: IdRange::max() } | |
317 | } | |
318 | ||
319 | pub fn result(&self) -> IdRange { | |
320 | self.result | |
321 | } | |
223e47cc LB |
322 | } |
323 | ||
1a4d82fc JJ |
324 | impl IdVisitingOperation for IdRangeComputingVisitor { |
325 | fn visit_id(&mut self, id: NodeId) { | |
326 | self.result.add(id); | |
970d7e83 LB |
327 | } |
328 | } | |
329 | ||
1a4d82fc | 330 | /// Computes the id range for a single fn body, ignoring nested items. |
e9174d1e | 331 | pub fn compute_id_range_for_fn_body(fk: FnKind, |
1a4d82fc JJ |
332 | decl: &FnDecl, |
333 | body: &Block, | |
334 | sp: Span, | |
335 | id: NodeId) | |
336 | -> IdRange | |
337 | { | |
e9174d1e | 338 | let mut visitor = IdRangeComputingVisitor::new(); |
1a4d82fc JJ |
339 | let mut id_visitor = IdVisitor { |
340 | operation: &mut visitor, | |
1a4d82fc JJ |
341 | visited_outermost: false, |
342 | }; | |
343 | id_visitor.visit_fn(fk, decl, body, sp, id); | |
344 | id_visitor.operation.result | |
970d7e83 LB |
345 | } |
346 | ||
1a4d82fc JJ |
347 | /// Returns true if the given pattern consists solely of an identifier |
348 | /// and false otherwise. | |
349 | pub fn pat_is_ident(pat: P<ast::Pat>) -> bool { | |
350 | match pat.node { | |
7453a54e | 351 | PatKind::Ident(..) => true, |
1a4d82fc JJ |
352 | _ => false, |
353 | } | |
970d7e83 LB |
354 | } |
355 | ||
1a4d82fc JJ |
356 | // are two paths equal when compared unhygienically? |
357 | // since I'm using this to replace ==, it seems appropriate | |
358 | // to compare the span, global, etc. fields as well. | |
359 | pub fn path_name_eq(a : &ast::Path, b : &ast::Path) -> bool { | |
7453a54e | 360 | (a.span.source_equal(&b.span)) |
1a4d82fc | 361 | && (a.global == b.global) |
85aaf69f | 362 | && (segments_name_eq(&a.segments[..], &b.segments[..])) |
970d7e83 LB |
363 | } |
364 | ||
1a4d82fc JJ |
365 | // are two arrays of segments equal when compared unhygienically? |
366 | pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> bool { | |
85aaf69f | 367 | a.len() == b.len() && |
62682a34 | 368 | a.iter().zip(b).all(|(s, t)| { |
85aaf69f SL |
369 | s.identifier.name == t.identifier.name && |
370 | // FIXME #7743: ident -> name problems in lifetime comparison? | |
371 | // can types contain idents? | |
372 | s.parameters == t.parameters | |
373 | }) | |
970d7e83 LB |
374 | } |
375 | ||
970d7e83 | 376 | #[cfg(test)] |
d9579d0f | 377 | mod tests { |
970d7e83 LB |
378 | use ast::*; |
379 | use super::*; | |
970d7e83 | 380 | |
b039eaaf SL |
381 | fn ident_to_segment(id: Ident) -> PathSegment { |
382 | PathSegment {identifier: id, | |
1a4d82fc | 383 | parameters: PathParameters::none()} |
970d7e83 LB |
384 | } |
385 | ||
1a4d82fc JJ |
386 | #[test] fn idents_name_eq_test() { |
387 | assert!(segments_name_eq( | |
b039eaaf SL |
388 | &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))] |
389 | .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>(), | |
390 | &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(78),SyntaxContext(182))] | |
391 | .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>())); | |
1a4d82fc | 392 | assert!(!segments_name_eq( |
b039eaaf SL |
393 | &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))] |
394 | .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>(), | |
395 | &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(77),SyntaxContext(182))] | |
396 | .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>())); | |
1a4d82fc | 397 | } |
970d7e83 | 398 | } |