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