]> git.proxmox.com Git - rustc.git/blob - src/librustc_front/util.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.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
19 pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool
20 where F: FnMut(&Pat) -> bool
21 {
22 // FIXME(#19596) this is a workaround, but there should be a better way
23 fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool
24 where G: FnMut(&Pat) -> bool
25 {
26 if !it(pat) {
27 return false;
28 }
29
30 match pat.node {
31 PatKind::Ident(_, _, Some(ref p)) => walk_pat_(&p, it),
32 PatKind::Struct(_, ref fields, _) => {
33 fields.iter().all(|field| walk_pat_(&field.node.pat, it))
34 }
35 PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => {
36 s.iter().all(|p| walk_pat_(&p, it))
37 }
38 PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
39 walk_pat_(&s, it)
40 }
41 PatKind::Vec(ref before, ref slice, ref after) => {
42 before.iter().all(|p| walk_pat_(&p, it)) &&
43 slice.iter().all(|p| walk_pat_(&p, it)) &&
44 after.iter().all(|p| walk_pat_(&p, it))
45 }
46 PatKind::Wild |
47 PatKind::Lit(_) |
48 PatKind::Range(_, _) |
49 PatKind::Ident(_, _, _) |
50 PatKind::TupleStruct(..) |
51 PatKind::Path(..) |
52 PatKind::QPath(_, _) => {
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: HirVec::new(),
339 ty_params: HirVec::new(),
340 where_clause: WhereClause {
341 id: DUMMY_NODE_ID,
342 predicates: HirVec::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: hir_vec![hir::PathSegment {
354 identifier: ident,
355 parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
356 lifetimes: HirVec::new(),
357 types: HirVec::new(),
358 bindings: HirVec::new(),
359 }),
360 }],
361 }
362 }