| // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| use hir; |
| use hir::*; |
| use intravisit::{self, Visitor, FnKind}; |
| use syntax::ast_util; |
| use syntax::ast::{Name, NodeId, DUMMY_NODE_ID}; |
| use syntax::codemap::Span; |
| use syntax::ptr::P; |
| |
| pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool |
| where F: FnMut(&Pat) -> bool |
| { |
| // FIXME(#19596) this is a workaround, but there should be a better way |
| fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool |
| where G: FnMut(&Pat) -> bool |
| { |
| if !(*it)(pat) { |
| return false; |
| } |
| |
| match pat.node { |
| PatIdent(_, _, Some(ref p)) => walk_pat_(&**p, it), |
| PatStruct(_, ref fields, _) => { |
| fields.iter().all(|field| walk_pat_(&*field.node.pat, it)) |
| } |
| PatEnum(_, Some(ref s)) | PatTup(ref s) => { |
| s.iter().all(|p| walk_pat_(&**p, it)) |
| } |
| PatBox(ref s) | PatRegion(ref s, _) => { |
| walk_pat_(&**s, it) |
| } |
| PatVec(ref before, ref slice, ref after) => { |
| before.iter().all(|p| walk_pat_(&**p, it)) && |
| slice.iter().all(|p| walk_pat_(&**p, it)) && |
| after.iter().all(|p| walk_pat_(&**p, it)) |
| } |
| PatWild | |
| PatLit(_) | |
| PatRange(_, _) | |
| PatIdent(_, _, _) | |
| PatEnum(_, _) | |
| PatQPath(_, _) => { |
| true |
| } |
| } |
| } |
| |
| walk_pat_(pat, &mut it) |
| } |
| |
| pub fn binop_to_string(op: BinOp_) -> &'static str { |
| match op { |
| BiAdd => "+", |
| BiSub => "-", |
| BiMul => "*", |
| BiDiv => "/", |
| BiRem => "%", |
| BiAnd => "&&", |
| BiOr => "||", |
| BiBitXor => "^", |
| BiBitAnd => "&", |
| BiBitOr => "|", |
| BiShl => "<<", |
| BiShr => ">>", |
| BiEq => "==", |
| BiLt => "<", |
| BiLe => "<=", |
| BiNe => "!=", |
| BiGe => ">=", |
| BiGt => ">", |
| } |
| } |
| |
| pub fn stmt_id(s: &Stmt) -> NodeId { |
| match s.node { |
| StmtDecl(_, id) => id, |
| StmtExpr(_, id) => id, |
| StmtSemi(_, id) => id, |
| } |
| } |
| |
| pub fn lazy_binop(b: BinOp_) -> bool { |
| match b { |
| BiAnd => true, |
| BiOr => true, |
| _ => false, |
| } |
| } |
| |
| pub fn is_shift_binop(b: BinOp_) -> bool { |
| match b { |
| BiShl => true, |
| BiShr => true, |
| _ => false, |
| } |
| } |
| |
| pub fn is_comparison_binop(b: BinOp_) -> bool { |
| match b { |
| BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true, |
| BiAnd | |
| BiOr | |
| BiAdd | |
| BiSub | |
| BiMul | |
| BiDiv | |
| BiRem | |
| BiBitXor | |
| BiBitAnd | |
| BiBitOr | |
| BiShl | |
| BiShr => false, |
| } |
| } |
| |
| /// Returns `true` if the binary operator takes its arguments by value |
| pub fn is_by_value_binop(b: BinOp_) -> bool { |
| !is_comparison_binop(b) |
| } |
| |
| /// Returns `true` if the unary operator takes its argument by value |
| pub fn is_by_value_unop(u: UnOp) -> bool { |
| match u { |
| UnNeg | UnNot => true, |
| _ => false, |
| } |
| } |
| |
| pub fn unop_to_string(op: UnOp) -> &'static str { |
| match op { |
| UnDeref => "*", |
| UnNot => "!", |
| UnNeg => "-", |
| } |
| } |
| |
| pub struct IdVisitor<'a, O: 'a> { |
| operation: &'a mut O, |
| |
| // In general, the id visitor visits the contents of an item, but |
| // not including nested trait/impl items, nor other nested items. |
| // The base visitor itself always skips nested items, but not |
| // trait/impl items. This means in particular that if you start by |
| // visiting a trait or an impl, you should not visit the |
| // trait/impl items respectively. This is handled by setting |
| // `skip_members` to true when `visit_item` is on the stack. This |
| // way, if the user begins by calling `visit_trait_item`, we will |
| // visit the trait item, but if they begin with `visit_item`, we |
| // won't visit the (nested) trait items. |
| skip_members: bool, |
| } |
| |
| impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> { |
| pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { |
| IdVisitor { operation: operation, skip_members: false } |
| } |
| |
| fn visit_generics_helper(&mut self, generics: &Generics) { |
| for type_parameter in generics.ty_params.iter() { |
| self.operation.visit_id(type_parameter.id) |
| } |
| for lifetime in &generics.lifetimes { |
| self.operation.visit_id(lifetime.lifetime.id) |
| } |
| } |
| } |
| |
| impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { |
| fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { |
| self.operation.visit_id(node_id); |
| intravisit::walk_mod(self, module) |
| } |
| |
| fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { |
| self.operation.visit_id(foreign_item.id); |
| intravisit::walk_foreign_item(self, foreign_item) |
| } |
| |
| fn visit_item(&mut self, item: &Item) { |
| assert!(!self.skip_members); |
| self.skip_members = true; |
| |
| self.operation.visit_id(item.id); |
| match item.node { |
| ItemUse(ref view_path) => { |
| match view_path.node { |
| ViewPathSimple(_, _) | |
| ViewPathGlob(_) => {} |
| ViewPathList(_, ref paths) => { |
| for path in paths { |
| self.operation.visit_id(path.node.id()) |
| } |
| } |
| } |
| } |
| _ => {} |
| } |
| intravisit::walk_item(self, item); |
| |
| self.skip_members = false; |
| } |
| |
| fn visit_local(&mut self, local: &Local) { |
| self.operation.visit_id(local.id); |
| intravisit::walk_local(self, local) |
| } |
| |
| fn visit_block(&mut self, block: &Block) { |
| self.operation.visit_id(block.id); |
| intravisit::walk_block(self, block) |
| } |
| |
| fn visit_stmt(&mut self, statement: &Stmt) { |
| self.operation.visit_id(stmt_id(statement)); |
| intravisit::walk_stmt(self, statement) |
| } |
| |
| fn visit_pat(&mut self, pattern: &Pat) { |
| self.operation.visit_id(pattern.id); |
| intravisit::walk_pat(self, pattern) |
| } |
| |
| fn visit_expr(&mut self, expression: &Expr) { |
| self.operation.visit_id(expression.id); |
| intravisit::walk_expr(self, expression) |
| } |
| |
| fn visit_ty(&mut self, typ: &Ty) { |
| self.operation.visit_id(typ.id); |
| intravisit::walk_ty(self, typ) |
| } |
| |
| fn visit_generics(&mut self, generics: &Generics) { |
| self.visit_generics_helper(generics); |
| intravisit::walk_generics(self, generics) |
| } |
| |
| fn visit_fn(&mut self, |
| function_kind: FnKind<'v>, |
| function_declaration: &'v FnDecl, |
| block: &'v Block, |
| span: Span, |
| node_id: NodeId) { |
| self.operation.visit_id(node_id); |
| |
| match function_kind { |
| FnKind::ItemFn(_, generics, _, _, _, _) => { |
| self.visit_generics_helper(generics) |
| } |
| FnKind::Method(_, sig, _) => { |
| self.visit_generics_helper(&sig.generics) |
| } |
| FnKind::Closure => {} |
| } |
| |
| for argument in &function_declaration.inputs { |
| self.operation.visit_id(argument.id) |
| } |
| |
| intravisit::walk_fn(self, function_kind, function_declaration, block, span); |
| } |
| |
| fn visit_struct_field(&mut self, struct_field: &StructField) { |
| self.operation.visit_id(struct_field.node.id); |
| intravisit::walk_struct_field(self, struct_field) |
| } |
| |
| fn visit_variant_data(&mut self, |
| struct_def: &VariantData, |
| _: Name, |
| _: &hir::Generics, |
| _: NodeId, |
| _: Span) { |
| self.operation.visit_id(struct_def.id()); |
| intravisit::walk_struct_def(self, struct_def); |
| } |
| |
| fn visit_trait_item(&mut self, ti: &hir::TraitItem) { |
| if !self.skip_members { |
| self.operation.visit_id(ti.id); |
| intravisit::walk_trait_item(self, ti); |
| } |
| } |
| |
| fn visit_impl_item(&mut self, ii: &hir::ImplItem) { |
| if !self.skip_members { |
| self.operation.visit_id(ii.id); |
| intravisit::walk_impl_item(self, ii); |
| } |
| } |
| |
| fn visit_lifetime(&mut self, lifetime: &Lifetime) { |
| self.operation.visit_id(lifetime.id); |
| } |
| |
| fn visit_lifetime_def(&mut self, def: &LifetimeDef) { |
| self.visit_lifetime(&def.lifetime); |
| } |
| |
| fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { |
| self.operation.visit_id(trait_ref.ref_id); |
| intravisit::walk_trait_ref(self, trait_ref); |
| } |
| } |
| |
| /// Computes the id range for a single fn body, ignoring nested items. |
| pub fn compute_id_range_for_fn_body(fk: FnKind, |
| decl: &FnDecl, |
| body: &Block, |
| sp: Span, |
| id: NodeId) |
| -> ast_util::IdRange { |
| let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() }; |
| let mut id_visitor = IdVisitor::new(&mut visitor); |
| id_visitor.visit_fn(fk, decl, body, sp, id); |
| id_visitor.operation.result |
| } |
| |
| pub fn is_path(e: P<Expr>) -> bool { |
| match e.node { |
| ExprPath(..) => true, |
| _ => false, |
| } |
| } |
| |
| pub fn empty_generics() -> Generics { |
| Generics { |
| lifetimes: HirVec::new(), |
| ty_params: HirVec::new(), |
| where_clause: WhereClause { |
| id: DUMMY_NODE_ID, |
| predicates: HirVec::new(), |
| }, |
| } |
| } |
| |
| // convert a span and an identifier to the corresponding |
| // 1-segment path |
| pub fn ident_to_path(s: Span, ident: Ident) -> Path { |
| hir::Path { |
| span: s, |
| global: false, |
| segments: hir_vec![hir::PathSegment { |
| identifier: ident, |
| parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { |
| lifetimes: HirVec::new(), |
| types: HirVec::new(), |
| bindings: HirVec::new(), |
| }), |
| }], |
| } |
| } |