]> git.lizzy.rs Git - rust.git/blob - src/librustc_front/util.rs
Use ast attributes every where (remove HIR attributes).
[rust.git] / src / librustc_front / util.rs
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
11 use hir;
12 use hir::*;
13 use visit::{self, Visitor, FnKind};
14 use syntax::ast_util;
15 use syntax::ast::{Ident, NodeId, DUMMY_NODE_ID};
16 use syntax::codemap::Span;
17 use syntax::ptr::P;
18 use syntax::owned_slice::OwnedSlice;
19
20 pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
21     // FIXME(#19596) this is a workaround, but there should be a better way
22     fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool where G: FnMut(&Pat) -> bool {
23         if !(*it)(pat) {
24             return false;
25         }
26
27         match pat.node {
28             PatIdent(_, _, Some(ref p)) => walk_pat_(&**p, it),
29             PatStruct(_, ref fields, _) => {
30                 fields.iter().all(|field| walk_pat_(&*field.node.pat, it))
31             }
32             PatEnum(_, Some(ref s)) | PatTup(ref s) => {
33                 s.iter().all(|p| walk_pat_(&**p, it))
34             }
35             PatBox(ref s) | PatRegion(ref s, _) => {
36                 walk_pat_(&**s, it)
37             }
38             PatVec(ref before, ref slice, ref after) => {
39                 before.iter().all(|p| walk_pat_(&**p, it)) &&
40                 slice.iter().all(|p| walk_pat_(&**p, it)) &&
41                 after.iter().all(|p| walk_pat_(&**p, it))
42             }
43             PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
44             PatEnum(_, _) | PatQPath(_, _) => {
45                 true
46             }
47         }
48     }
49
50     walk_pat_(pat, &mut it)
51 }
52
53 pub fn binop_to_string(op: BinOp_) -> &'static str {
54     match op {
55         BiAdd => "+",
56         BiSub => "-",
57         BiMul => "*",
58         BiDiv => "/",
59         BiRem => "%",
60         BiAnd => "&&",
61         BiOr => "||",
62         BiBitXor => "^",
63         BiBitAnd => "&",
64         BiBitOr => "|",
65         BiShl => "<<",
66         BiShr => ">>",
67         BiEq => "==",
68         BiLt => "<",
69         BiLe => "<=",
70         BiNe => "!=",
71         BiGe => ">=",
72         BiGt => ">"
73     }
74 }
75
76 /// Returns true if the given struct def is tuple-like; i.e. that its fields
77 /// are unnamed.
78 pub fn struct_def_is_tuple_like(struct_def: &hir::StructDef) -> bool {
79     struct_def.ctor_id.is_some()
80 }
81
82 pub fn stmt_id(s: &Stmt) -> NodeId {
83     match s.node {
84       StmtDecl(_, id) => id,
85       StmtExpr(_, id) => id,
86       StmtSemi(_, id) => id,
87     }
88 }
89
90 pub fn lazy_binop(b: BinOp_) -> bool {
91     match b {
92       BiAnd => true,
93       BiOr => true,
94       _ => false
95     }
96 }
97
98 pub fn is_shift_binop(b: BinOp_) -> bool {
99     match b {
100       BiShl => true,
101       BiShr => true,
102       _ => false
103     }
104 }
105
106 pub fn is_comparison_binop(b: BinOp_) -> bool {
107     match b {
108         BiEq | BiLt | BiLe | BiNe | BiGt | BiGe =>
109             true,
110         BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem |
111         BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr =>
112             false,
113     }
114 }
115
116 /// Returns `true` if the binary operator takes its arguments by value
117 pub fn is_by_value_binop(b: BinOp_) -> bool {
118     !is_comparison_binop(b)
119 }
120
121 /// Returns `true` if the unary operator takes its argument by value
122 pub fn is_by_value_unop(u: UnOp) -> bool {
123     match u {
124         UnNeg | UnNot => true,
125         _ => false,
126     }
127 }
128
129 pub fn unop_to_string(op: UnOp) -> &'static str {
130     match op {
131       UnUniq => "box() ",
132       UnDeref => "*",
133       UnNot => "!",
134       UnNeg => "-",
135     }
136 }
137
138 pub struct IdVisitor<'a, O:'a> {
139     pub operation: &'a mut O,
140     pub pass_through_items: bool,
141     pub visited_outermost: bool,
142 }
143
144 impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> {
145     fn visit_generics_helper(&mut self, generics: &Generics) {
146         for type_parameter in generics.ty_params.iter() {
147             self.operation.visit_id(type_parameter.id)
148         }
149         for lifetime in &generics.lifetimes {
150             self.operation.visit_id(lifetime.lifetime.id)
151         }
152     }
153 }
154
155 impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
156     fn visit_mod(&mut self,
157                  module: &Mod,
158                  _: Span,
159                  node_id: NodeId) {
160         self.operation.visit_id(node_id);
161         visit::walk_mod(self, module)
162     }
163
164     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
165         self.operation.visit_id(foreign_item.id);
166         visit::walk_foreign_item(self, foreign_item)
167     }
168
169     fn visit_item(&mut self, item: &Item) {
170         if !self.pass_through_items {
171             if self.visited_outermost {
172                 return
173             } else {
174                 self.visited_outermost = true
175             }
176         }
177
178         self.operation.visit_id(item.id);
179         match item.node {
180             ItemUse(ref view_path) => {
181                 match view_path.node {
182                     ViewPathSimple(_, _) |
183                     ViewPathGlob(_) => {}
184                     ViewPathList(_, ref paths) => {
185                         for path in paths {
186                             self.operation.visit_id(path.node.id())
187                         }
188                     }
189                 }
190             }
191             ItemEnum(ref enum_definition, _) => {
192                 for variant in &enum_definition.variants {
193                     self.operation.visit_id(variant.node.id)
194                 }
195             }
196             _ => {}
197         }
198
199         visit::walk_item(self, item);
200
201         self.visited_outermost = false
202     }
203
204     fn visit_local(&mut self, local: &Local) {
205         self.operation.visit_id(local.id);
206         visit::walk_local(self, local)
207     }
208
209     fn visit_block(&mut self, block: &Block) {
210         self.operation.visit_id(block.id);
211         visit::walk_block(self, block)
212     }
213
214     fn visit_stmt(&mut self, statement: &Stmt) {
215         self.operation.visit_id(stmt_id(statement));
216         visit::walk_stmt(self, statement)
217     }
218
219     fn visit_pat(&mut self, pattern: &Pat) {
220         self.operation.visit_id(pattern.id);
221         visit::walk_pat(self, pattern)
222     }
223
224     fn visit_expr(&mut self, expression: &Expr) {
225         self.operation.visit_id(expression.id);
226         visit::walk_expr(self, expression)
227     }
228
229     fn visit_ty(&mut self, typ: &Ty) {
230         self.operation.visit_id(typ.id);
231         visit::walk_ty(self, typ)
232     }
233
234     fn visit_generics(&mut self, generics: &Generics) {
235         self.visit_generics_helper(generics);
236         visit::walk_generics(self, generics)
237     }
238
239     fn visit_fn(&mut self,
240                 function_kind: FnKind<'v>,
241                 function_declaration: &'v FnDecl,
242                 block: &'v Block,
243                 span: Span,
244                 node_id: NodeId) {
245         if !self.pass_through_items {
246             match function_kind {
247                 FnKind::Method(..) if self.visited_outermost => return,
248                 FnKind::Method(..) => self.visited_outermost = true,
249                 _ => {}
250             }
251         }
252
253         self.operation.visit_id(node_id);
254
255         match function_kind {
256             FnKind::ItemFn(_, generics, _, _, _, _) => {
257                 self.visit_generics_helper(generics)
258             }
259             FnKind::Method(_, sig, _) => {
260                 self.visit_generics_helper(&sig.generics)
261             }
262             FnKind::Closure => {}
263         }
264
265         for argument in &function_declaration.inputs {
266             self.operation.visit_id(argument.id)
267         }
268
269         visit::walk_fn(self,
270                        function_kind,
271                        function_declaration,
272                        block,
273                        span);
274
275         if !self.pass_through_items {
276             if let FnKind::Method(..) = function_kind {
277                 self.visited_outermost = false;
278             }
279         }
280     }
281
282     fn visit_struct_field(&mut self, struct_field: &StructField) {
283         self.operation.visit_id(struct_field.node.id);
284         visit::walk_struct_field(self, struct_field)
285     }
286
287     fn visit_struct_def(&mut self,
288                         struct_def: &StructDef,
289                         _: Ident,
290                         _: &hir::Generics,
291                         id: NodeId) {
292         self.operation.visit_id(id);
293         struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
294         visit::walk_struct_def(self, struct_def);
295     }
296
297     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
298         self.operation.visit_id(ti.id);
299         visit::walk_trait_item(self, ti);
300     }
301
302     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
303         self.operation.visit_id(ii.id);
304         visit::walk_impl_item(self, ii);
305     }
306
307     fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) {
308         self.operation.visit_id(lifetime.id);
309     }
310
311     fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
312         self.visit_lifetime_ref(&def.lifetime);
313     }
314
315     fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
316         self.operation.visit_id(trait_ref.ref_id);
317         visit::walk_trait_ref(self, trait_ref);
318     }
319 }
320
321 /// Computes the id range for a single fn body, ignoring nested items.
322 pub fn compute_id_range_for_fn_body(fk: FnKind,
323                                     decl: &FnDecl,
324                                     body: &Block,
325                                     sp: Span,
326                                     id: NodeId)
327                                     -> ast_util::IdRange
328 {
329     let mut visitor = ast_util::IdRangeComputingVisitor {
330         result: ast_util::IdRange::max()
331     };
332     let mut id_visitor = IdVisitor {
333         operation: &mut visitor,
334         pass_through_items: false,
335         visited_outermost: false,
336     };
337     id_visitor.visit_fn(fk, decl, body, sp, id);
338     id_visitor.operation.result
339 }
340
341 pub fn is_path(e: P<Expr>) -> bool {
342     match e.node { ExprPath(..) => true, _ => false }
343 }
344
345 pub fn empty_generics() -> Generics {
346     Generics {
347         lifetimes: Vec::new(),
348         ty_params: OwnedSlice::empty(),
349         where_clause: WhereClause {
350             id: DUMMY_NODE_ID,
351             predicates: Vec::new(),
352         }
353     }
354 }
355
356 // convert a span and an identifier to the corresponding
357 // 1-segment path
358 pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
359     hir::Path {
360         span: s,
361         global: false,
362         segments: vec!(
363             hir::PathSegment {
364                 identifier: identifier,
365                 parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
366                     lifetimes: Vec::new(),
367                     types: OwnedSlice::empty(),
368                     bindings: OwnedSlice::empty(),
369                 })
370             }
371         ),
372     }
373 }