|
27 | 27 |
|
28 | 28 | use syntax::abi::Abi;
|
29 | 29 | use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
|
| 30 | +use syntax::ast_util; |
30 | 31 | use syntax::attr::ThinAttributesExt;
|
31 | 32 | use syntax::codemap::Span;
|
32 | 33 | use hir::*;
|
@@ -835,3 +836,185 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
|
835 | 836 | visitor.visit_expr(&arm.body);
|
836 | 837 | walk_list!(visitor, visit_attribute, &arm.attrs);
|
837 | 838 | }
|
| 839 | + |
| 840 | +pub struct IdVisitor<'a, O: 'a> { |
| 841 | + operation: &'a mut O, |
| 842 | + |
| 843 | + // In general, the id visitor visits the contents of an item, but |
| 844 | + // not including nested trait/impl items, nor other nested items. |
| 845 | + // The base visitor itself always skips nested items, but not |
| 846 | + // trait/impl items. This means in particular that if you start by |
| 847 | + // visiting a trait or an impl, you should not visit the |
| 848 | + // trait/impl items respectively. This is handled by setting |
| 849 | + // `skip_members` to true when `visit_item` is on the stack. This |
| 850 | + // way, if the user begins by calling `visit_trait_item`, we will |
| 851 | + // visit the trait item, but if they begin with `visit_item`, we |
| 852 | + // won't visit the (nested) trait items. |
| 853 | + skip_members: bool, |
| 854 | +} |
| 855 | + |
| 856 | +impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> { |
| 857 | + pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { |
| 858 | + IdVisitor { operation: operation, skip_members: false } |
| 859 | + } |
| 860 | + |
| 861 | + fn visit_generics_helper(&mut self, generics: &Generics) { |
| 862 | + for type_parameter in generics.ty_params.iter() { |
| 863 | + self.operation.visit_id(type_parameter.id) |
| 864 | + } |
| 865 | + for lifetime in &generics.lifetimes { |
| 866 | + self.operation.visit_id(lifetime.lifetime.id) |
| 867 | + } |
| 868 | + } |
| 869 | +} |
| 870 | + |
| 871 | +impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { |
| 872 | + fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { |
| 873 | + self.operation.visit_id(node_id); |
| 874 | + walk_mod(self, module) |
| 875 | + } |
| 876 | + |
| 877 | + fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { |
| 878 | + self.operation.visit_id(foreign_item.id); |
| 879 | + walk_foreign_item(self, foreign_item) |
| 880 | + } |
| 881 | + |
| 882 | + fn visit_item(&mut self, item: &Item) { |
| 883 | + assert!(!self.skip_members); |
| 884 | + self.skip_members = true; |
| 885 | + |
| 886 | + self.operation.visit_id(item.id); |
| 887 | + match item.node { |
| 888 | + ItemUse(ref view_path) => { |
| 889 | + match view_path.node { |
| 890 | + ViewPathSimple(_, _) | |
| 891 | + ViewPathGlob(_) => {} |
| 892 | + ViewPathList(_, ref paths) => { |
| 893 | + for path in paths { |
| 894 | + self.operation.visit_id(path.node.id()) |
| 895 | + } |
| 896 | + } |
| 897 | + } |
| 898 | + } |
| 899 | + _ => {} |
| 900 | + } |
| 901 | + walk_item(self, item); |
| 902 | + |
| 903 | + self.skip_members = false; |
| 904 | + } |
| 905 | + |
| 906 | + fn visit_local(&mut self, local: &Local) { |
| 907 | + self.operation.visit_id(local.id); |
| 908 | + walk_local(self, local) |
| 909 | + } |
| 910 | + |
| 911 | + fn visit_block(&mut self, block: &Block) { |
| 912 | + self.operation.visit_id(block.id); |
| 913 | + walk_block(self, block) |
| 914 | + } |
| 915 | + |
| 916 | + fn visit_stmt(&mut self, statement: &Stmt) { |
| 917 | + self.operation.visit_id(statement.node.id()); |
| 918 | + walk_stmt(self, statement) |
| 919 | + } |
| 920 | + |
| 921 | + fn visit_pat(&mut self, pattern: &Pat) { |
| 922 | + self.operation.visit_id(pattern.id); |
| 923 | + walk_pat(self, pattern) |
| 924 | + } |
| 925 | + |
| 926 | + fn visit_expr(&mut self, expression: &Expr) { |
| 927 | + self.operation.visit_id(expression.id); |
| 928 | + walk_expr(self, expression) |
| 929 | + } |
| 930 | + |
| 931 | + fn visit_ty(&mut self, typ: &Ty) { |
| 932 | + self.operation.visit_id(typ.id); |
| 933 | + walk_ty(self, typ) |
| 934 | + } |
| 935 | + |
| 936 | + fn visit_generics(&mut self, generics: &Generics) { |
| 937 | + self.visit_generics_helper(generics); |
| 938 | + walk_generics(self, generics) |
| 939 | + } |
| 940 | + |
| 941 | + fn visit_fn(&mut self, |
| 942 | + function_kind: FnKind<'v>, |
| 943 | + function_declaration: &'v FnDecl, |
| 944 | + block: &'v Block, |
| 945 | + span: Span, |
| 946 | + node_id: NodeId) { |
| 947 | + self.operation.visit_id(node_id); |
| 948 | + |
| 949 | + match function_kind { |
| 950 | + FnKind::ItemFn(_, generics, _, _, _, _, _) => { |
| 951 | + self.visit_generics_helper(generics) |
| 952 | + } |
| 953 | + FnKind::Method(_, sig, _, _) => { |
| 954 | + self.visit_generics_helper(&sig.generics) |
| 955 | + } |
| 956 | + FnKind::Closure(_) => {} |
| 957 | + } |
| 958 | + |
| 959 | + for argument in &function_declaration.inputs { |
| 960 | + self.operation.visit_id(argument.id) |
| 961 | + } |
| 962 | + |
| 963 | + walk_fn(self, function_kind, function_declaration, block, span); |
| 964 | + } |
| 965 | + |
| 966 | + fn visit_struct_field(&mut self, struct_field: &StructField) { |
| 967 | + self.operation.visit_id(struct_field.id); |
| 968 | + walk_struct_field(self, struct_field) |
| 969 | + } |
| 970 | + |
| 971 | + fn visit_variant_data(&mut self, |
| 972 | + struct_def: &VariantData, |
| 973 | + _: Name, |
| 974 | + _: &Generics, |
| 975 | + _: NodeId, |
| 976 | + _: Span) { |
| 977 | + self.operation.visit_id(struct_def.id()); |
| 978 | + walk_struct_def(self, struct_def); |
| 979 | + } |
| 980 | + |
| 981 | + fn visit_trait_item(&mut self, ti: &TraitItem) { |
| 982 | + if !self.skip_members { |
| 983 | + self.operation.visit_id(ti.id); |
| 984 | + walk_trait_item(self, ti); |
| 985 | + } |
| 986 | + } |
| 987 | + |
| 988 | + fn visit_impl_item(&mut self, ii: &ImplItem) { |
| 989 | + if !self.skip_members { |
| 990 | + self.operation.visit_id(ii.id); |
| 991 | + walk_impl_item(self, ii); |
| 992 | + } |
| 993 | + } |
| 994 | + |
| 995 | + fn visit_lifetime(&mut self, lifetime: &Lifetime) { |
| 996 | + self.operation.visit_id(lifetime.id); |
| 997 | + } |
| 998 | + |
| 999 | + fn visit_lifetime_def(&mut self, def: &LifetimeDef) { |
| 1000 | + self.visit_lifetime(&def.lifetime); |
| 1001 | + } |
| 1002 | + |
| 1003 | + fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { |
| 1004 | + self.operation.visit_id(trait_ref.ref_id); |
| 1005 | + walk_trait_ref(self, trait_ref); |
| 1006 | + } |
| 1007 | +} |
| 1008 | + |
| 1009 | +/// Computes the id range for a single fn body, ignoring nested items. |
| 1010 | +pub fn compute_id_range_for_fn_body(fk: FnKind, |
| 1011 | + decl: &FnDecl, |
| 1012 | + body: &Block, |
| 1013 | + sp: Span, |
| 1014 | + id: NodeId) |
| 1015 | + -> ast_util::IdRange { |
| 1016 | + let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() }; |
| 1017 | + let mut id_visitor = IdVisitor::new(&mut visitor); |
| 1018 | + id_visitor.visit_fn(fk, decl, body, sp, id); |
| 1019 | + id_visitor.operation.result |
| 1020 | +} |
0 commit comments