Clean up classification of relevant types for codegen
diff --git a/syn_codegen/src/main.rs b/syn_codegen/src/main.rs
index 072744c..20dfddb 100644
--- a/syn_codegen/src/main.rs
+++ b/syn_codegen/src/main.rs
@@ -63,7 +63,7 @@
 
 #[derive(Clone)]
 pub struct AstItem {
-    item: DeriveInput,
+    ast: DeriveInput,
     features: Tokens,
     // True if this is an ast_enum_of_structs! item with a #full annotation.
     eos_full: bool,
@@ -72,7 +72,7 @@
 impl Debug for AstItem {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.debug_struct("AstItem")
-            .field("item", &self.item)
+            .field("ast", &self.ast)
             .field("features", &self.features.to_string())
             .finish()
     }
@@ -145,14 +145,14 @@
                 // Record our features on the parsed AstItems.
                 for mut item in found {
                     features.to_tokens(&mut item.features);
-                    lookup.insert(item.item.ident, item);
+                    lookup.insert(item.ast.ident, item);
                 }
             }
             Item::Struct(item) => {
                 let ident = item.ident;
                 if EXTRA_TYPES.contains(&ident.as_ref()) {
                     lookup.insert(ident, AstItem {
-                        item: DeriveInput {
+                        ast: DeriveInput {
                             ident: ident,
                             vis: item.vis,
                             attrs: item.attrs,
@@ -209,7 +209,7 @@
         option!(manual_extra_traits) >>
         rest: syn!(TokenStream) >>
         (AstItem {
-            item: parse_tokens::<DeriveInput>(quote! {
+            ast: parse_tokens::<DeriveInput>(quote! {
                 pub struct #id #rest
             })?,
             features: features.0,
@@ -234,7 +234,7 @@
     impl Synom for AstEnum {
         named!(parse -> Self, map!(braces!(syn!(DeriveInput)), |x| {
             AstEnum(vec![AstItem {
-                item: x.0,
+                ast: x.0,
                 features: quote!(),
                 eos_full: false,
             }])
@@ -252,7 +252,7 @@
         keyword!(pub) >>
         variant: syn!(Ident) >>
         member: map!(parens!(alt!(
-            call!(ast_struct_inner) => { |x: AstItem| (Path::from(x.item.ident), Some(x)) }
+            call!(ast_struct_inner) => { |x: AstItem| (Path::from(x.ast.ident), Some(x)) }
             |
             syn!(Path) => { |x| (x, None) }
         )), |x| x.0) >>
@@ -288,7 +288,7 @@
                     })?
                 };
                 let mut items = vec![AstItem {
-                    item: enum_item,
+                    ast: enum_item,
                     features: quote!(),
                     eos_full:  false,
                 }];
@@ -320,21 +320,34 @@
         name.as_ref().to_snake_case().into()
     }
 
-    fn last_segment(ty: &Type) -> Option<&PathSegment> {
-        match *ty {
-            Type::Path(ref typath) => {
-                if typath.qself.is_some() {
-                    return None;
-                }
-                let name = if let Some(name) = typath.path.segments.last() {
-                    name
-                } else {
-                    return None;
-                };
+    enum RelevantType<'a> {
+        Box(&'a Type),
+        Vec(&'a Type),
+        Delimited(&'a Type),
+        Option(&'a Type),
+        Simple(&'a AstItem),
+        Pass,
+    }
 
-                Some(name.item())
+    fn classify<'a>(ty: &'a Type, lookup: &'a Lookup) -> RelevantType<'a> {
+        match *ty {
+            Type::Path(TypePath { qself: None, ref path }) => {
+                let last = path.segments.last().unwrap().into_item();
+                match last.ident.as_ref() {
+                    "Box" => RelevantType::Box(first_arg(&last.arguments)),
+                    "Vec" => RelevantType::Vec(first_arg(&last.arguments)),
+                    "Delimited" => RelevantType::Delimited(first_arg(&last.arguments)),
+                    "Option" => RelevantType::Option(first_arg(&last.arguments)),
+                    _ => {
+                        if let Some(item) = lookup.get(&last.ident) {
+                            RelevantType::Simple(item)
+                        } else {
+                            RelevantType::Pass
+                        }
+                    }
+                }
             }
-            _ => None,
+            _ => RelevantType::Pass,
         }
     }
 
@@ -405,38 +418,37 @@
     }
 
     fn simple_visit(
-        type_name: Ident,
+        item: &AstItem,
         kind: Kind,
         name: &Operand,
     ) -> String {
         match kind {
             Visit => format!(
                 "_visitor.visit_{under_name}({name})",
-                under_name = under_name(type_name),
+                under_name = under_name(item.ast.ident),
                 name = name.ref_tokens(),
             ),
             VisitMut => format!(
                 "_visitor.visit_{under_name}_mut({name})",
-                under_name = under_name(type_name),
+                under_name = under_name(item.ast.ident),
                 name = name.ref_mut_tokens(),
             ),
             Fold => format!(
                 "_visitor.fold_{under_name}({name})",
-                under_name = under_name(type_name),
+                under_name = under_name(item.ast.ident),
                 name = name.owned_tokens(),
             ),
         }
     }
 
     fn box_visit(
-        seg: &PathSegment,
+        elem: &Type,
         lookup: &Lookup,
         kind: Kind,
         name: &Operand,
     ) -> Option<String> {
-        let ty = first_arg(&seg.arguments);
         let name = name.owned_tokens();
-        let res = visit(&ty, lookup, kind, &Owned(quote!(*#name)))?;
+        let res = visit(&elem, lookup, kind, &Owned(quote!(*#name)))?;
         Some(match kind {
             Fold => format!("Box::new({})", res),
             Visit | VisitMut => res,
@@ -444,54 +456,70 @@
     }
 
     fn vec_visit(
-        seg: &PathSegment,
+        elem: &Type,
         lookup: &Lookup,
         kind: Kind,
         name: &Operand,
     ) -> Option<String> {
-        let is_vec = seg.ident == "Vec";
-        let ty = first_arg(&seg.arguments);
         let operand = match kind {
             Visit | VisitMut => Borrowed(quote!(it)),
             Fold => Owned(quote!(it)),
         };
-        let val = visit(&ty, lookup, kind, &operand)?;
+        let val = visit(&elem, lookup, kind, &operand)?;
         Some(match kind {
             Visit => {
-                if is_vec {
-                    format!(
-                        "for it in {name} {{ {val} }}",
-                        name = name.ref_tokens(),
-                        val = val,
-                    )
-                } else {
-                    format!(
-                        "for el in {name} {{ \
-                            let it = el.item(); \
-                            {val} \
-                            }}",
-                        name = name.ref_tokens(),
-                        val = val,
-                    )
-                }
+                format!(
+                    "for it in {name} {{ {val} }}",
+                    name = name.ref_tokens(),
+                    val = val,
+                )
             }
             VisitMut => {
-                if is_vec {
-                    format!(
-                        "for it in {name} {{ {val} }}",
-                        name = name.ref_mut_tokens(),
-                        val = val,
-                    )
-                } else {
-                    format!(
-                        "for mut el in {name} {{ \
-                            let it = el.item_mut(); \
-                            {val} \
-                            }}",
-                        name = name.ref_mut_tokens(),
-                        val = val,
-                    )
-                }
+                format!(
+                    "for it in {name} {{ {val} }}",
+                    name = name.ref_mut_tokens(),
+                    val = val,
+                )
+            }
+            Fold => format!(
+                "FoldHelper::lift({name}, |it| {{ {val} }})",
+                name = name.owned_tokens(),
+                val = val,
+            ),
+        })
+    }
+
+    fn delimited_visit(
+        elem: &Type,
+        lookup: &Lookup,
+        kind: Kind,
+        name: &Operand,
+    ) -> Option<String> {
+        let operand = match kind {
+            Visit | VisitMut => Borrowed(quote!(it)),
+            Fold => Owned(quote!(it)),
+        };
+        let val = visit(&elem, lookup, kind, &operand)?;
+        Some(match kind {
+            Visit => {
+                format!(
+                    "for el in {name} {{ \
+                        let it = el.item(); \
+                        {val} \
+                        }}",
+                    name = name.ref_tokens(),
+                    val = val,
+                )
+            }
+            VisitMut => {
+                format!(
+                    "for mut el in {name} {{ \
+                        let it = el.item_mut(); \
+                        {val} \
+                        }}",
+                    name = name.ref_mut_tokens(),
+                    val = val,
+                )
             }
             Fold => format!(
                 "FoldHelper::lift({name}, |it| {{ {val} }})",
@@ -502,17 +530,16 @@
     }
 
     fn option_visit(
-        seg: &PathSegment,
+        elem: &Type,
         lookup: &Lookup,
         kind: Kind,
         name: &Operand,
     ) -> Option<String> {
-        let ty = first_arg(&seg.arguments);
         let it = match kind {
             Visit | VisitMut => Borrowed(quote!(it)),
             Fold => Owned(quote!(it)),
         };
-        let val = visit(&ty, lookup, kind, &it)?;
+        let val = visit(&elem, lookup, kind, &it)?;
         Some(match kind {
             Visit => format!(
                 "if let Some(ref it) = {name} {{ {val} }}",
@@ -540,30 +567,35 @@
     }
 
     fn visit(ty: &Type, lookup: &Lookup, kind: Kind, name: &Operand) -> Option<String> {
-        let seg = last_segment(ty)?;
-        match seg.ident.as_ref() {
-            "Box" => {
-                box_visit(seg, lookup, kind, name)
+        match classify(ty, lookup) {
+            RelevantType::Box(elem) => {
+                box_visit(elem, lookup, kind, name)
             }
-            "Vec" | "Delimited" => {
-                vec_visit(seg, lookup, kind, name)
+            RelevantType::Vec(elem) => {
+                vec_visit(elem, lookup, kind, name)
             }
-            "Option" => {
-                option_visit(seg, lookup, kind, name)
+            RelevantType::Delimited(elem) => {
+                delimited_visit(elem, lookup, kind, name)
             }
-            _ => {
-                let s = lookup.get(&seg.ident)?;
-                let mut res = simple_visit(seg.ident, kind, name);
-                if s.eos_full {
-                    res = format!("full!({res})", res = res);
-                }
-                Some(res)
+            RelevantType::Option(elem) => {
+                option_visit(elem, lookup, kind, name)
+            }
+            RelevantType::Simple(item) => {
+                let mut res = simple_visit(item, kind, name);
+                Some(if item.eos_full {
+                    format!("full!({res})", res = res)
+                } else {
+                    res
+                })
+            }
+            RelevantType::Pass => {
+                None
             }
         }
     }
 
     pub fn generate(state: &mut State, lookup: &Lookup, s: &AstItem) {
-        let under_name = under_name(s.item.ident);
+        let under_name = under_name(s.ast.ident);
 
         state.visit_trait.push_str(&format!(
             "{features}\n\
@@ -572,7 +604,7 @@
              }}\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
         state.visit_mut_trait.push_str(&format!(
             "{features}\n\
@@ -581,7 +613,7 @@
              }}\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
         state.fold_trait.push_str(&format!(
             "{features}\n\
@@ -590,7 +622,7 @@
              }}\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
 
         state.visit_impl.push_str(&format!(
@@ -599,7 +631,7 @@
              _visitor: &mut V, _i: &'ast {ty}) {{\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
         state.visit_mut_impl.push_str(&format!(
             "{features}\n\
@@ -607,7 +639,7 @@
              _visitor: &mut V, _i: &mut {ty}) {{\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
         state.fold_impl.push_str(&format!(
             "{features}\n\
@@ -615,13 +647,13 @@
              _visitor: &mut V, _i: {ty}) -> {ty} {{\n",
             features = s.features,
             under_name = under_name,
-            ty = s.item.ident,
+            ty = s.ast.ident,
         ));
 
         // XXX:  This part is a disaster - I'm not sure how to make it cleaner though :'(
-        match s.item.body {
+        match s.ast.body {
             Body::Enum(ref e) => {
-                let use_decl = format!("    use ::{}::*;\n", s.item.ident);
+                let use_decl = format!("    use ::{}::*;\n", s.ast.ident);
                 state.visit_impl.push_str(&use_decl);
                 state.visit_mut_impl.push_str(&use_decl);
                 state.fold_impl.push_str(&use_decl);
@@ -739,7 +771,7 @@
                     VariantData::Struct(ref fields, ..) => {
                         state
                             .fold_impl
-                            .push_str(&format!("    {} {{\n", s.item.ident));
+                            .push_str(&format!("    {} {{\n", s.ast.ident));
                         fields
                             .iter()
                             .map(|el| {
@@ -751,7 +783,7 @@
                     VariantData::Tuple(ref fields, ..) => {
                         state
                             .fold_impl
-                            .push_str(&format!("    {} (\n", s.item.ident));
+                            .push_str(&format!("    {} (\n", s.ast.ident));
                         fields
                             .iter()
                             .enumerate()
@@ -825,7 +857,7 @@
         lookup.insert(
             Ident::from(tt),
             AstItem {
-                item: DeriveInput {
+                ast: DeriveInput {
                     ident: Ident::from(tt),
                     vis: Visibility::Public(VisPublic {
                         pub_token: Default::default(),